Istio安全-认证(istio 系列七)
Istio安全-认证
认证策略
本节会介绍如何启用,配置和使用istio的认证策略,了解更多关于认证的底层概念。
首先了解istio的认证策略和相关的mutual TLS认证概念,然后使用default
配置安装istio
配置
下面例子会创建两个命名空间foo
和bar
,以及两个服务httpbin
和sleep
,这两个服务都运行了Envoy代理。其次还在legacy
命名空间中运行了不带sidecar的httpbin
和sleep
的实例。最好使用自动注入sidecar的方式。
$ kubectl create ns foo
$ kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml) -n foo
$ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n foo
$ kubectl create ns bar
$ kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml) -n bar
$ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n bar
$ kubectl create ns legacy
$ kubectl apply -f samples/httpbin/httpbin.yaml -n legacy
$ kubectl apply -f samples/sleep/sleep.yaml -n legacy
使用curl验证配置是否正确,从foo
, bar
或legacy
中的sleep pod向httpbin.foo
, httpbin.bar
或httpbin.legacy
发送HTTP请求,所有的请求都应该返回HTTP 200状态码。
$ kubectl exec $(kubectl get pod -l app=sleep -n bar -o jsonpath={.items..metadata.name}) -c sleep -n bar -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "%{http_code}\n"
下面命令可以方便地遍历所有可达性组合:
$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar" "legacy"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.foo to httpbin.legacy: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
sleep.bar to httpbin.legacy: 200
sleep.legacy to httpbin.foo: 200
sleep.legacy to httpbin.bar: 200
sleep.legacy to httpbin.legacy: 200
校验没有配置对等认证策略
$ kubectl get peerauthentication --all-namespaces
No resources found.
校验没有为例子的服务配置任何destination rules。可以通过校验现有destination rules是否存在host:
来查看是否存在匹配的内容:
$ kubectl get destinationrules.networking.istio.io --all-namespaces -o yaml | grep "host:"
自动mutual TLS
默认情况下,istio会跟踪迁移到Istio代理的服务器工作负载,并自动配置客户端代理发送mutual TLS流量到这些负载,并发送明文流量到没有sidecar的负载。
因此拥有代理的负载之间的流量会使用mutual TLS。例如,获取发送到httpbin/header
的请求对应的响应,当使用mutual TLS时,代理会在到达后端的上游请求中注入 X-Forwarded-Client-Cert
首部。出现该首部表明使用了mutual TLS:
$ kubectl exec $(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name}) -c sleep -n foo -- curl http://httpbin.foo:8000/headers -s | grep X-Forwarded-Client-Cert
"X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/foo/sa/httpbin;Hash=4b69f5cb0582b9a06f2178666d1fc082ec7538aa76eb29e28a5e048713ced049;Subject=\"\";URI=spiffe://cluster.local/ns/foo/sa/sleep"
当服务端没有sidecar,则请求中不会被注入 X-Forwarded-Client-Cert
首部,暗示请求使用了明文:
$ kubectl exec $(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name}) -c sleep -n foo -- curl http://httpbin.legacy:8000/headers -s | grep X-Forwarded-Client-Cert
全局启用istio的mutual TLS STRIC模式
由于istio会自动将代理和负载之间的流量升级到mutual TLS,此时负载仍然接收明文流量。为了防止整个网格中出现非mutual TLS,需要在网格范围将对等认证策略设置为mutual TLS STRICT
。网格范围的对等认证策略不应该出现selector
字段,且必须应用到根命名空间:
$ kubectl apply -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "default"
namespace: "istio-system"
spec:
mtls:
mode: STRICT
EOF
注:上例中将
istio-system
假设为根命名空间,如果安装时选用了不同的命名空间,则使用该命名空间替换istio-system
对等认证策略会产生如下影响:网格中所有的负载只能接收使用TLS加密的请求。由于没有使用selector
字段指定值,因此该策略会应用到网格中的所有负载。
重新执行如下命令:
$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar" "legacy"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.foo to httpbin.legacy: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
sleep.bar to httpbin.legacy: 200
sleep.legacy to httpbin.foo: 000
command terminated with exit code 56
sleep.legacy to httpbin.bar: 000
command terminated with exit code 56
sleep.legacy to httpbin.legacy: 200
可以看到不包含代理的客户端(sleep.legacy
)的到包含代理的服务端(httpbin.foo
或httpbin.bar
.)的请求失败了。由于此时使用了严格的mutual TLS,但不包含代理的负载无法满足该要求。
卸载
$ kubectl delete peerauthentication -n istio-system default
针对单个命名空间或负载启用mutual TLS
命名空间范围的策略
为了修改特定命名空间内的所有负载的mutual TLS,需要使用命名空间范围的策略。命名空间范围的策略与网格范围的策略的规范相同,但需要在metadata
下指定命名空间。例如,下面在foo
命名空间中启用了严格的mutual TLS对等认证策略。
$ kubectl apply -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "default"
namespace: "foo"
spec:
mtls:
mode: STRICT
EOF
由于该策略仅对foo命名空间生效,可以看到只有sleep.legacy
(不包含代理)到 httpbin.foo
的请求失败了
$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar" "legacy"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.foo to httpbin.legacy: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
sleep.bar to httpbin.legacy: 200
sleep.legacy to httpbin.foo: 000
command terminated with exit code 56
sleep.legacy to httpbin.bar: 200
sleep.legacy to httpbin.legacy: 200
为单个负载启用mutual TLS
为了给特定的负载设置对等认证策略,需要使用selector
字段指定匹配到期望负载的标签。然而,Istio无法为(到达服务的)出站的mutual TLS流量聚合工作负载级别的策略(可以理解为对等认证策略是匹配负载(如pod)的,还需要destination rule匹配服务(DNS)),需要配置destination rule管理该行为。
例如,下面对等认证策略和destination rule为httpbin.bar
负载启用了严格的mutual TLS。
$ cat <<EOF | kubectl apply -n bar -f -
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "httpbin"
namespace: "bar"
spec:
selector:
matchLabels:
app: httpbin
mtls:
mode: STRICT
EOF
$ cat <<EOF | kubectl apply -n bar -f -
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
name: "httpbin"
spec:
host: "httpbin.bar.svc.cluster.local"
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
EOF
执行探测命令,可以看到sleep.legacy
到httpbin.bar
的请求失败了。
$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar" "legacy"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.foo to httpbin.legacy: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
sleep.bar to httpbin.legacy: 200
sleep.legacy to httpbin.foo: 000
command terminated with exit code 56
sleep.legacy to httpbin.bar: 000
command terminated with exit code 56
sleep.legacy to httpbin.legacy: 200
如果要为单个端口设置mutual TLS,则需要配置portLevelMtls
字段。例如,下面对等认证策略需要在除了80
的端口上启用mutual TLS
$ cat <<EOF | kubectl apply -n bar -f -
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "httpbin"
namespace: "bar"
spec:
selector:
matchLabels:
app: httpbin
mtls:
mode: STRICT
portLevelMtls:
80:
mode: DISABLE
EOF
此时也需要一个destination rule
$ cat <<EOF | kubectl apply -n bar -f -
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
name: "httpbin"
spec:
host: httpbin.bar.svc.cluster.local
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
portLevelSettings:
- port:
number: 8000
tls:
mode: DISABLE
EOF
- 对等认证策略中的端口值为容器的端口,而destination rule中的值为service的端口
- 仅当端口绑定到服务时才能使用
portLevelMtls
。其他情况下,istio会忽略该字段
策略优先级
指定负载的对等认证策略要优先于命名空间范围的策略。可以通过禁用httpbin.foo
负载的mutual TLS来测试这种特性。注意,foo命名空间已经启用了命名空间范围的mutual TLS,从sleep.legacy
到httpbin.foo
的请求会失败(见上文)。
$ cat <<EOF | kubectl apply -n foo -f -
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "overwrite-example"
namespace: "foo"
spec:
selector:
matchLabels:
app: httpbin
mtls:
mode: DISABLE
EOF
$ cat <<EOF | kubectl apply -n foo -f -
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
name: "overwrite-example"
spec:
host: httpbin.foo.svc.cluster.local
trafficPolicy:
tls:
mode: DISABLE
EOF
重新从sleep.legacy
发起请求,可以看到成功返回200,表明指定服务的策略要优先于指定命名空间的策略。
$ kubectl exec $(kubectl get pod -l app=sleep -n legacy -o jsonpath={.items..metadata.name}) -c sleep -n legacy -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "%{http_code}\n"
200
此时foo
命名空间中有2个对等认证策略。
$ oc get peerauthentications.security.istio.io
NAME AGE
default 16h
overwrite-example 106s
卸载
$ kubectl delete peerauthentication default overwrite-example -n foo
$ kubectl delete peerauthentication httpbin -n bar
$ kubectl delete destinationrules overwrite-example -n foo
$ kubectl delete destinationrules httpbin -n bar
终端用户认证
为了试验该特性,需要一个有效的JWT。JWT必须与使用的JWKS终端相匹配。本节测试JWT test 和JWKS endpoint。
为了方便,通过ingressgateway
暴露httpbin.foo
。
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
namespace: foo
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
EOF
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
namespace: foo
spec:
hosts:
- "*"
gateways:
- httpbin-gateway
http:
- route:
- destination:
port:
number: 8000
host: httpbin.foo.svc.cluster.local
EOF
获取ingress IP
$ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
运行一个测试请求。PS:官方文档好像有点问题,直接在ingressgateway pod中执行测试
# curl 127.0.0.1:8080/headers -s -o /dev/null -w "%{http_code}\n"
200
为ingress gateway添加一个需要终端用户JWT的请求认证策略
$ kubectl apply -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "RequestAuthentication"
metadata:
name: "jwt-example"
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
jwtRules:
- issuer: "testing@secure.istio.io"
jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.6/security/tools/jwt/samples/jwks.json"
EOF
将该策略应用到负载(ingressgateway
)上,选择的命名空间为istio-system
。
如果在认证首部提供了token,istio会使用公钥集进行认证,如果token无效,则请求会被拒绝。但是会接收不带token的请求。为了观察这种行为,发送不带token,带错误的token和带无效token的请求。
# curl 127.0.0.1:8080/headers -s -o /dev/null -w "%{http_code}\n"
200
# curl --header "Authorization: Bearer deadbeef" 127.0.0.1:8080/headers -s -o /dev/null -w "%{http_code}\n"
401
# curl --header "Authorization: Bearer $TOKEN" 127.0.0.1:8080/headers -s -o /dev/null -w "%{http_code}\n"
200
为了观察JWT验证的其他方面,使用 gen-jwt.py
生成新的token来测试不同的issuer,audiences,expiry date等。该脚本可以从istio的库中下载:
$ wget https://raw.githubusercontent.com/istio/istio/release-1.6/security/tools/jwt/samples/gen-jwt.py
$ chmod +x gen-jwt.py
此外还需要用到key.pem
文件
$ wget https://raw.githubusercontent.com/istio/istio/release-1.6/security/tools/jwt/samples/key.pem
例如,一下命令会创建一个token,5s过期。可以看到istio认证请求一开始是成功的,5s后会被拒绝。
$ TOKEN=$(./gen-jwt.py ./key.pem --expire 5)
$ for i in `seq 1 10`; do curl --header "Authorization: Bearer $TOKEN" $INGRESS_HOST/headers -s -o /dev/null -w "%{http_code}\n"; sleep 1; done
200
200
200
200
200
401
401
401
401
401
也可以给ingress gateway配置一个JWT策略。通常用于为绑定到网关的所有服务定义JWT策略,而不只为单个服务定义JWT策略。
请求有效的token
为了拒绝不带有效token的请求,需要添加一个DENY
字段来处理无请求主体的请求,如下的notRequestPrincipals: ["*"]
。只有提供了有效的JWT token后,才会认为请求主体是有效的。下面规则会拒绝没有有效token的请求。
$ kubectl apply -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: "frontend-ingress"
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
action: DENY
rules:
- from:
- source:
notRequestPrincipals: ["*"]
EOF
重新请求,可以发现此时不带token的请求返回了403错误码:
# curl 127.0.0.1:8080/headers -s -o /dev/null -w "%{http_code}\n"
403
为每条路径请求有效的token
要使用基于每个主机、路径或方法的token来优化授权,需要将授权策略更改为只对/headers生效。当授权规则生效时,对 $INGRESS_HOST/headers
的请求会返回错误码403,而针对其他路径的请求则会成功,如$INGRESS_HOST/ip
。
$ kubectl apply -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: "frontend-ingress"
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
action: DENY
rules:
- from:
- source:
notRequestPrincipals: ["*"]
to:
- operation:
paths: ["/headers"]
EOF
# curl 127.0.0.1:8080/headers -s -o /dev/null -w "%{http_code}\n"
403
# curl 127.0.0.1:8080/ip -s -o /dev/null -w "%{http_code}\n"
200
卸载
移除认证策略
$ kubectl -n istio-system delete requestauthentication jwt-example
$ kubectl -n istio-system delete authorizationpolicy frontend-ingress
移除pod
$ kubectl delete ns foo bar legacy
Mutual TLS迁移
本节展示如何保证负载迁移到istio后仅使用mutual TLS通信。
当调用其它负载时,istio会自动配置负载sidecar使用mutual TLS。istio默认会使用PERMISSIVE
模式配置目标负载。当启用PERMISSIVE
模式时,服务可以同时接收明文和mutual TLS的流量。为了仅允许mutual TLS流量,需要将配置切换为STRICT
模式。
可以使用Grafana dashboard校验哪些负载会发送明文流量到使用PERMISSIVE模式的负载。
配置集群
创建两个命名空间,foo
和bar
,部署带sidecar的httpbin和sleep
$ kubectl create ns foo
$ kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml) -n foo
$ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n foo
$ kubectl create ns bar
$ kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml) -n bar
$ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n bar
创建另外一个命名空间legacy
,并部署不带sidecar的sleep
$ kubectl create ns legacy
$ kubectl apply -f samples/sleep/sleep.yaml -n legacy
从三个命名空间的sleep pod中发送请求到httpbin.foo
,所有的请求都应该返回HTTP 200状态码。
$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar"; do kubectl exec "$(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name})" -c sleep -n ${from} -- curl http://httpbin.${to}:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
sleep.legacy to httpbin.foo: 200
sleep.legacy to httpbin.bar: 200
保证没有认证策略或destination rules
$ kubectl get peerauthentication --all-namespaces | grep -v istio-system
NAMESPACE NAME AGE
$ kubectl get destinationrule --all-namespaces
No resources found.
按命名空间锁定mutual TLS
在将所有的客户端迁移到istio并注入Envoy sidecar后,配置foo命名空间仅允许接收mutual TLS流量。
$ kubectl apply -n foo -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "default"
spec:
mtls:
mode: STRICT
EOF
此时从 sleep.legacy
到 httpbin.foo
的请求会失败:
$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar"; do kubectl exec "$(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name})" -c sleep -n ${from} -- curl http://httpbin.${to}:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
sleep.legacy to httpbin.foo: 000
command terminated with exit code 56
sleep.legacy to httpbin.bar: 200
如果在安装istio时启用了 values.global.proxy.privileged=true
,则可以使用tcpdump
校验流量是否加密。
$ kubectl exec -nfoo "$(kubectl get pod -nfoo -lapp=httpbin -ojsonpath={.items..metadata.name})" -c istio-proxy -it -- sudo tcpdump dst port 80 -A
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
如果无法将所有的服务迁移到istio,则需要使用PERMiISSIVE
模式。但是如果使用了PERMISSIVE模式,则不会使用任何认证和授权,默认使用明文流量。推荐使用istio认证为不同的路径配置不同的策略。
为整个网格锁定mutual TLS
$ kubectl apply -n istio-system -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "default"
spec:
mtls:
mode: STRICT
EOF
现在 foo
和bar
命名空间会强制使用mutual TLS流量,因此从sleep.legacy
发出的所有请求都会失败。
$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar"; do kubectl exec "$(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name})" -c sleep -n ${from} -- curl http://httpbin.${to}:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
sleep.legacy to httpbin.foo: 000
command terminated with exit code 56
sleep.legacy to httpbin.bar: 000
command terminated with exit code 56
卸载
$ kubectl delete peerauthentication --all-namespaces --all
kubectl delete ns foo bar legacy
Istio安全-认证(istio 系列七)的更多相关文章
- 【译文连载】 理解Istio服务网格(第七章 安全)
全书目录 第一章 概述 第二章 安装 第三章 流控 第四章 服务弹性 第五章 混沌测试 第六章 可观测性 本文目录 第7章 安全 7.1 身份认证 7.1.1 Kubernetes上的Istio的身份 ...
- Istio 运维实战系列(2):让人头大的『无头服务』-上
本系列文章将介绍用户从 Spring Cloud,Dubbo 等传统微服务框架迁移到 Istio 服务网格时的一些经验,以及在使用 Istio 过程中可能遇到的一些常见问题的解决方法. 什么是『无头服 ...
- Istio 运维实战系列(3):让人头大的『无头服务』-下
本系列文章将介绍用户从 Spring Cloud,Dubbo 等传统微服务框架迁移到 Istio 服务网格时的一些经验,以及在使用 Istio 过程中可能遇到的一些常见问题的解决方法. 失败的 Eur ...
- openshift 4.3 Istio的搭建(istio 系列一)
openshift 4.3 Istio的搭建 本文档覆盖了官方文档的Setup的所有章节 目录 openshift 4.3 Istio的搭建 安装Istio openshift安装Istio 更新is ...
- Istio(九):istio安全之授权
目录 一.模块概览 二.系统环境 三.istio授权 3.1 istio授权 3.2 来源 3.3 操作 3.4 条件 四.实战:授权(访问控制) 4.1 访问控制 4.2 清理 一.模块概览 在Ku ...
- WCF编程系列(七)信道及信道工厂
WCF编程系列(七)信道及信道工厂 信道及信道栈 前面已经提及过,WCF中客户端与服务端的交互都是通过消息来进行的.消息从客户端传送到服务端会经过多个处理动作,在WCF编程模型中,这些动作是按层 ...
- SQL Server 2008空间数据应用系列七:基于Bing Maps(Silverlight) 的空间数据展现
原文:SQL Server 2008空间数据应用系列七:基于Bing Maps(Silverlight) 的空间数据展现 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft ...
- C语言高速入口系列(七)
C语言高速入口系列(七) C语言指针进阶 本章引言: 在前面第5节中我们对C语言的指针进行了初步的学习理解;作为C语言的灵魂, C指针肯定没那么简单,在这一节中,我们将会对指针进行进一步的学习,比方二 ...
- 7.oracle学习门户系列七---网络管理和配置
oracle学习门户系列七 网络管理和配置 们学习了模式和用户.包含模式定义以及模式的作用. 这篇我么来看下ORACLE数据库中的网络管理和配置.只是这篇好像和上篇没有继承啊.这怎么看? Ok,事实上 ...
随机推荐
- Android学习笔记尺寸资源
尺寸资源语法 dp:设备独立资源像素 会根据设备匹配大小 一般用于设置边距和组件大小 sp : 可伸缩像素 根据用户手机字体大小首选项进行缩放 使用尺寸资源 定义尺寸资源 dimens <?xm ...
- 《Java并发编程的艺术》第5章 Java中的锁 ——学习笔记
参考https://www.cnblogs.com/lilinzhiyu/p/8125195.html 5.1 Lock接口 锁是用来控制多个线程访问共享资源的方式. 一般来说一个锁可以防止多个线程同 ...
- C# 实现定时/循环任务
用C#实现定时/循环任务,需要使用到Quartz,在项目的NuGet包管理中可以找到并添加.一般还会伴随安装一个Log4Net,主要用它来记录在任务执行过程中遇到的问题.这边主要是讲实现定时/循环任务 ...
- windows10安装配置WSL(Ubuntu)
windows10安装配置WSL(Ubuntu) 怎么在windows系统上用上Linux?有这么几种方法: 1. 安装双系统.这种方法的缺点是每次切换系统都需要关机.切换系统. 2. 虚拟机+Lin ...
- CentOS 7 下安装 MySQL 8.0
前言 本篇文章主要介绍在 CentOS 7 环境下安装 MySQL 8.0. 正文 1. 配置yum源 首先在 https://dev.mysql.com/downloads/repo/yum/ 找到 ...
- eclipse在debug模式下鼠标移动到变量上不显示值的问题
在eclipse中调试时,鼠标移动到变量上不显示值,使用ctrl+shift+i,或者通过配置达到目的: Window->Preferences->Java->Editor-> ...
- C++版的网络数据包解析策略(升级版)
初版:http://www.cnblogs.com/wjshan0808/p/6580638.html 说明:在实现了对应的接口后该策略可以适合绝大多数的网络数据包结构 首先,是三个接口 IProdu ...
- vs2013, EF6.0.0.0 使用Migrations来更新数据库时报错
1.vs中,程序包管理器控制台 2.执行,Enable-Migrations 报错: Migrations have already been enabled in project 'dd'. To ...
- 我打算用JAVA实现GB/T32960 监控平台的tcp server
之前是用golang写得 ,因为对golang不是很熟练,打算基于netty再写一个,开源出来. 如果近期时间宽裕,就准备着手了. 有兴趣的朋友也可以留言一起做.
- windows快速安装redis
下载地址:https://github.com/microsoftarchive/redis/releases 下载解压,命令行:redis-server.exe redis.windows.conf