网站设计与制作一般步骤长白山网站学做管理平台

pingmian/2026/1/24 7:47:32/文章来源:
网站设计与制作一般步骤,长白山网站学做管理平台,做全景哪个网站不模糊,济南seo优化外包服务公司目录 文章目录 目录本节实战1、安全概述2、证书签发流程1.签发证书2.身份认证 3、认证1.对等认证a.默认的宽容模式b.全局严格 mTLS 模式c.命名空间级别策略d.为每个工作负载启用双向 TLS 2.请求认证a.JWK 与 JWKS 概述b.配置 JWT 终端用户认证c.设置强制认证规则 关于我最后 本… 目录 文章目录 目录本节实战1、安全概述2、证书签发流程1.签发证书2.身份认证 3、认证1.对等认证a.默认的宽容模式b.全局严格 mTLS 模式c.命名空间级别策略d.为每个工作负载启用双向 TLS 2.请求认证a.JWK 与 JWKS 概述b.配置 JWT 终端用户认证c.设置强制认证规则 关于我最后 本节实战 实战名称 实战对等认证(默认的宽容模式)-2023.11.24(测速成功) 实战对等认证(全局严格 mTLS 模式)-2023.11.24(测速成功) 实战对等认证(命名空间级别策略)-2023.11.24(测速成功) 实战对等认证(为每个工作负载启用双向 TLS)-2023.11.24(测速成功) 实战对等认证(为每个端口配置不同的对等认证策略)-2023.11.24(测速成功) 实战请求认证-2023.11.25(测试成功) 1、安全概述 安全是一个非常重要的话题但也是平时容易被忽略的一个话题我们在开发应用的时候往往会忽略安全但是当应用上线后安全问题就会暴露出来这时候就会造成很大的损失。Istio 通过在服务之间注入 Sidecar 代理来实现对服务之间的流量进行控制和监控从而实现服务之间的安全通信。 接下来我们将从**证书管理、认证、授权**等几个方面来学习 Istio 的安全机制。 将单一应用程序拆分为微服务可提供各种好处包括更好的灵活性、可伸缩性以及服务复用的能力。但是微服务也有特殊的安全需求 为了抵御中间人攻击需要流量加密。为了提供灵活的服务访问控制需要双向 TLS 和细粒度的访问策略。要确定谁在什么时候做了什么需要审计工具。 Istio 尝试提供全面的安全解决方案来解决所有这些问题Istio 安全性可以减轻针对你的数据、端点、通信和平台的内外威胁。 Istio 为微服务提供了无侵入可插拔的安全框架。应用不需要修改代码就可以利用 Istio 提供的双向 TLS 认证实现服务身份认证并基于服务身份信息提供细粒度的访问控制。Istio 安全的高层架构如下图所示 上图展示了 Istio 中的服务认证和授权两部分。服务认证是通过控制面和数据面一起实现的 控制面Istiod 中实现了一个 CA Certificate Authority证书机构 服务器。该 CA 服务器负责为网格中的各个服务签发证书并将证书分发给数据面的各个服务的边车代理。数据面在网格中的服务相互之间发起 plain(原始的未加密的) HTTP/TCP 通信时和服务同一个 pod 中的边车代理会拦截服务请求采用证书和对端服务的边车代理进行双向 TLS 认证并建立一个 TLS 连接使用该 TLS 连接来在网络中传输数据。 Istio 的授权功能为网格中的工作负载提供网格、命名空间和工作负载级别的访问控制这种控制层级提供了许多优点 工作负载到工作负载以及最终用户到工作负载的授权。一个简单的 API它包括一个单独的并且很容易使用和维护的 AuthorizationPolicy CRD。灵活的语义运维人员可以在 Istio 属性上定义自定义条件并使用 DENY 和 ALLOW 动作。高性能Istio 授权是在 Envoy 本地强制执行的。高兼容性原生支持 HTTP、HTTPS 和 HTTP2以及任意普通 TCP 协议。 **授权策略对服务器端 Envoy 代理的入站流量实施访问控制。**每个 Envoy 代理都运行一个授权引擎该引擎在运行时授权请求。当请求到达代理时授权引擎根据当前授权策略评估请求上下文并返回授权结果 ALLOW 或 DENY。运维人员可以通过 YAML 资源清单文件来指定 Istio 授权策略。 2、证书签发流程 默认情况下Istio CA 生成自签名根证书和密钥并使用它们来签署工作负载证书。为了保护根 CA 密钥我们应该使用在安全机器上离线运行的根 CA比如使用 Hashicorp Vault 进行管理并使用根 CA 向每个集群中运行的 Istio CA 颁发中间证书。Istio CA 可以使用管理员指定的证书和密钥对工作负载证书进行签名并将管理员指定的根证书作为信任根分发给工作负载。 1.签发证书 当我们有了 Istio CA 根证书后就可以使用它来签发工作负载证书了那么整个的证书签发流程又是怎样的呢如下图所示 Envoy 向 pilot-agent 发起一个 SDS (Secret Discovery Service) 请求启动的时候要求获取自己的证书和私钥。pilot-agent 生成私钥和 CSR 证书签名请求向 Istiod 发送证书签发请求请求中包含 CSR 和该 Pod 中服务的身份信息。Istiod 提供 gRPC 服务以接受证书签名请求根据请求中服务的身份信息如果是 Kubernetes 则使用 Service Account为其签发证书将证书返回给 pilot-agent。pilot-agent 将证书和私钥通过 SDS 接口返回给 Envoy。pilot-agent 还会监控工作负载证书的过期时间上述过程会定期重复进行证书和密钥轮换。 这个流程和我们自己用手动方式去进行证书签发是一样的所以我们需要先了解下证书签发的流程。Istio CA 根证书就是一个证书颁发机构平时如果要为我们自己的网站申请 HTTPS 证书我们也是去一些正规的 CA 机构进行申请而这个申请的信息就是生成的 CSR 证书签名请求然后我们将这个 CSR 和身份信息提交给 CA 机构CA 机构根据这些信息为我们签发证书然后我们就可以使用这个证书了只是我们这里在不同的组件上来执行这些操作整体流程是一样的。 istio-ca-root-cert [rootmaster1 ~]#kubectl get cm -nistio-system NAME DATA AGE …… istio-ca-root-cert 1 15d …… [rootmaster1 ~]#[rootmaster1 ~]#kubectl get po istiod-644f5d55fc-gs96f -nistio-system -oyaml ……- mountPath: /var/run/secrets/istiod/caname: istio-csr-ca-configmapreadOnly: true……- configMap:defaultMode: 420name: istio-ca-root-certoptional: truename: istio-csr-ca-configmap 2.身份认证 另外要通过服务证书来实现网格中服务的身份认证必须首先确保服务从控制面获取自身证书的流程是安全的。Istio 通过 Istiod 和 pilog-agent 之间的 gRPC 通道传递 CSR 和证书因此在这两个组件进行通信时双方需要先验证对方的身份以避免恶意第三方伪造 CSR 请求或者假冒 Istiod CA 服务器。Istio 中主要包含下面两种认证方式 Istiod 身份认证 Istiod 采用其内置的 CA 服务器为自身签发一个服务器证书并采用该服务器证书对外提供基于 TLS 的 gPRC 服务。 Istiod 调用 Kubernetes APIServer 生成一个名为 istio-ca-root-cert 的 ConfigMap 对象 在该 ConfigMap 中放入了 Istiod 的 CA 根证书。 该 ConfigMap 被 Mount 到 istio-proxy 容器中被 pilot-agent 用于验证 Istiod 的服务器证书。 在 pilot-agent 和 Istiod 建立 gRPC 连接时pilot-agent 采用标准的 TLS 服务器认证流程对 Istiod 的服务器证书进行认证。 pilot-agent 身份认证 在 Kubernetes 中可以为每一个 Pod 关联一个 ServiceAccount以表明该 Pod 中运行的服务的身份信息。 Kubernetes 会为该 ServiceAccount 生成一个 jwt token并将该 token 通过 secret 加载到 pod 中的一个文件。 pilot-agent 在向 Istiod 发送 CSR 时将其所在 Pod 的 service account token 也随请求发送给 Istiod。 Istiod 调用 Kube-apiserver 接口验证请求中附带的 service account token以确认请求证书的服务身份是否合法。 这里需要注意的是不同版本的 Kubernetes 集群下面的 ServiceAccount Token 生成方式并不一样但最终都是通过改 Token 来进行身份认证的。 1.20含 1.20之前的版本在创建 sa 时会自动创建一个 secret然后这个会把这个 secret 通过投射卷挂载到 pod 里该 secret 里面包含的 token 是永久有效的。1.21~1.23 版本在创建 sa 时也会自动创建 secret但是在 pod 里并不会使用 secret 里的 token而是由 kubelet 到 TokenRequest API 去申请一个 token该 token 默认有效期为一年但是 pod 每一个小时会更新一次 token。1.24 版本及以上在创建 sa 时不再自动创建 secret 了只保留由 kubelet 到 TokenRequest API 去申请 token。 3、认证 Istio 提供两种类型的认证用于管控网格服务间的双向 TLS 和终端用户的身份认证。 对等认证用于服务到服务的认证以验证建立连接的客户端。Istio 提供双向 TLS 作为传输认证的全栈解决方案无需更改服务代码就可以启用它。这个解决方案 为每个服务提供代表其角色的强大身份以实现跨集群和云的互操作性。 确保服务间通信的安全。 提供密钥管理系统以自动进行密钥和证书的生成、分发和轮换。 请求认证用于终端用户认证以验证附加到请求的凭据。Istio 使用 JSON Web TokenJWT验证启用请求级认证并使用自定义认证实现或任何 OpenID Connect 的认证实现来简化的开发人员体验。 1.对等认证 a.默认的宽容模式 实战对等认证(默认的宽容模式)-2023.11.24(测速成功) 实验环境 k8s v1.27.6containerd://1.6.20cniflannel:v0.22.2 istio v1.19.3(--set profiledemo)实验软件 链接https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd7yqb 提取码7yqb 2023.11.5-实战BookInfo 示例应用-2023.11.5(测试成功) 下面我们来创建几个示例服务来对认证配置进行测试。 这里我们将在 foo 和 bar 命名空间下各自创建带有 Envoy 代理Sidecar的 httpbin 和 sleep 服务。还将在 legacy 命名空间下创建不带 Envoy 代理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 barkubectl create ns legacy kubectl apply -f samples/httpbin/httpbin.yaml -n legacy kubectl apply -f samples/sleep/sleep.yaml -n legacy查看 [rootmaster1 istio-1.19.3]#kubectl get po -nfoo NAME READY STATUS RESTARTS AGE httpbin-5c44d89fd9-pmzkk 2/2 Running 0 3m43s sleep-844db44b8c-49br9 2/2 Running 0 3m42s [rootmaster1 istio-1.19.3]#kubectl get po -nbar NAME READY STATUS RESTARTS AGE httpbin-5c44d89fd9-zpdww 2/2 Running 0 3m43s sleep-844db44b8c-q688w 2/2 Running 0 3m42s [rootmaster1 istio-1.19.3]#kubectl get po -nlegacy NAME READY STATUS RESTARTS AGE httpbin-86869bccff-2cmj2 1/1 Running 0 3m47s sleep-9454cc476-vvr4q 1/1 Running 0 3m44s现在可以在 foo、bar 或 legacy 三个命名空间下的任意 sleep Pod 中使用 curl 向 httpbin.foo、httpbin.bar 或 httpbin.legacy 发送 HTTP 请求来验证部署结果所有请求都应该成功并返回 HTTP 200。 例如验证 sleep.bar 到 httpbin.foo 可达性如下 $ kubectl exec $(kubectl get pod -l appsleep -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 200也可以使用一行指令检查所有可能的组合 $ for from in foo bar legacy; do for to in foo bar legacy; do kubectl exec $(kubectl get pod -l appsleep -n ${from} -o jsonpath{.items..metadata.name}) -c sleep -n ${from} -- curl -s 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这样保证了我们的服务之间是可以互相访问的。 接下来我们就来看下如何对服务进行认证。 默认情况下在 Istio 网格内部的服务之间的所有流量都是通过双向 TLS 进行加密的不需要做额外的操作当使用双向 TLS 时代理会将 X-Forwarded-Client-Cert 这个 Header 头注入到后端的上游请求这个头信息的存在就是启用双向 TLS 的证据。例如 $ kubectl exec $(kubectl get pod -l appsleep -n foo -o jsonpath{.items..metadata.name}) -c sleep -n foo -- curl -s http://httpbin.foo:8000/headers -s {headers: {Accept: */*,Host: httpbin.foo:8000,User-Agent: curl/7.81.0-DEV,X-B3-Parentspanid: a59be7609a15c41f,X-B3-Sampled: 1,X-B3-Spanid: 034af52cfc2286b4,X-B3-Traceid: eb07847c5c14c17fa59be7609a15c41f,X-Envoy-Attempt-Count: 1,X-Forwarded-Client-Cert: Byspiffe://cluster.local/ns/foo/sa/httpbin;Hashbb907e90c93bc3f1dd22763f952746e7d2b8c5ad7903ecbcc64324f3b5e55179;Subject\\;URIspiffe://cluster.local/ns/foo/sa/sleep} }可以看到上面我们的请求中包含了 X-Forwarded-Client-Cert 这个 Header 头这就是启用双向 TLS 的证据得到的这个值是一个 spiffe:// 开头的字符串这个字符串就是 SPIFFE ID这个 SPIFFE ID 就是用来表示服务的身份的后面我们会详细介绍 SPIFFE。 **零信任架构**下需要严格区分工作负载的识别和信任而签发 X.509 证书是推荐的一种认证方式在 Kubernetes 集群中服务间是通过 DNS 名称互相访问的而网络流量可能被 DNS 欺骗、BGP/路由劫持、ARP 欺骗等手段劫持为了将服务名称DNS 名称与服务身份强关联起来Istio 使用置于 X.509 证书中的安全命名Secure naming机制。 SPIFFE 是 Istio 所采用的安全命名的规范它也是云原生定义的一种标准化的、可移植的工作负载身份规范。Secure Production Identity Framework For Everyone (SPIFFE) 是一套服务之间相互进行身份识别的标准主要包含以下内容 SPIFFE ID 标准SPIFFE ID 是服务的唯一标识具体实现使用 URI 资源标识符。SPIFFE Verifiable Identity Document (SVID) 标准将 SPIFFE ID 编码到一个加密的可验证的数据格式中。颁发与撤销 SVID 的 API 标准。 SPIFFE ID 规定了形如 spiffe://trust domain/workload identifier 的 URI 格式作为工作负载Workload的唯一标识。Istio 使用形如 spiffe://trust_domain/ns/namespace/sa/service_account 格式的 SPIFFE ID 作为安全命名注入到 X.509 证书的 subjectAltName 扩展中。其中的 trust domain 参数通过 Istiod 环境变量 TRUST_DOMAIN 注入用于在多集群环境中交互比如我们这里就是 cluster.local所以其实最终在 Envoy 的配置中可以看到匹配证书的 subjectAltName 值也是这个格式 {combined_validation_context: {default_validation_context: {match_subject_alt_names: [{exact: spiffe://cluster.local/ns/istio-system/sa/istiod}]},validation_context_sds_secret_config: {name: ROOTCA,sds_config: {api_config_source: {api_type: GRPC,grpc_services: [{envoy_grpc: {cluster_name: sds-grpc}}],set_node_on_first_message_only: true,transport_api_version: V3},initial_fetch_timeout: 0s,resource_api_version: V3}}} }当服务器没有 Sidecar 时X-Forwarded-Client-Cert 这个 Header 头将不会存在这意味着请求是明文的比如我们请求 httpbin.legacy 服务 [rootmaster1 istio-1.19.3]#kubectl exec $(kubectl get pod -l appsleep -n foo -o jsonpath{.items..metadata.name}) -c sleep -n foo -- curl http://httpbin.legacy:8000/headers -s {headers: {Accept: */*, Host: httpbin.legacy:8000, User-Agent: curl/7.81.0-DEV, X-B3-Sampled: 1, X-B3-Spanid: 1385a68dd52bc759, X-B3-Traceid: 94d64875182fd6101385a68dd52bc759, X-Envoy-Attempt-Count: 1, X-Envoy-Decorator-Operation: httpbin.legacy.svc.cluster.local:8000/*, X-Envoy-Peer-Metadata: ChkKDkFQUF9DT05UQUlORVJTEgcaBXNsZWVwChoKCkNMVVNURVJfSUQSDBoKS3ViZXJuZXRlcwodCgxJTlNUQU5DRV9JUFMSDRoLMTAuMjQ0LjIuMjIKGQoNSVNUSU9fVkVSU0lPThIIGgYxLjE5LjMKoQEKBkxBQkVMUxKWASqTAQoOCgNhcHASBxoFc2xlZXAKJAoZc2VjdXJpdHkuaXN0aW8uaW8vdGxzTW9kZRIHGgVpc3RpbwoqCh9zZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1uYW1lEgcaBXNsZWVwCi8KI3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLXJldmlzaW9uEggaBmxhdGVzdAoaCgdNRVNIX0lEEg8aDWNsdXN0ZXIubG9jYWwKIAoETkFNRRIYGhZzbGVlcC04NDRkYjQ0YjhjLTQ5YnI5ChIKCU5BTUVTUEFDRRIFGgNmb28, X-Envoy-Peer-Metadata-Id: sidecar~10.244.2.22~sleep-844db44b8c-49br9.foo~foo.svc.cluster.local} }[rootmaster1 istio-1.19.3]#kubectl exec $(kubectl get pod -l appsleep -n foo -o jsonpath{.items..metadata.name}) -c sleep -n foo -- curl http://httpbin.legacy:8000/headers -s | grep X-Forwarded-Client-Certb.全局严格 mTLS 模式 实战对等认证(全局严格 mTLS 模式)-2023.11.24(测速成功) 实验环境 k8s v1.27.6containerd://1.6.20cniflannel:v0.22.2 istio v1.19.3(--set profiledemo)实验软件 链接https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd7yqb 提取码7yqb 2023.11.5-实战BookInfo 示例应用-2023.11.5(测试成功) 事实上当 Istio 自动将代理和工作负载之间的所有流量升级到双向 TLS 时工作负载仍然可以接收明文流量如果想要禁用非 mTLS 的通信流量我们可以使用一个 PeerAuthentication 资源对象来进行配置只需要将整个网格的对等认证策略设置为 STRICT 模式作用域为整个网格范围的对等认证策略不设置 selector 即可这种认证策略必须应用于根命名空间istiod 所在的命名空间例如 创建下资源 #peer-strict-global.yaml apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication # 对等认证策略 metadata:name: defaultnamespace: istio-system spec:mtls:mode: STRICT # STRICT 模式表示只允许 mTLS对等认证策略指定 Istio 对目标工作负载实施的双向 TLS 模式。支持以下模式 PERMISSIVE工作负载接受双向 TLS 和纯文本流量也就是所谓的宽容模式。此模式在迁移因为没有 Sidecar 而无法使用双向 TLS 的工作负载的过程中非常有用。一旦工作负载完成 Sidecar 注入的迁移应将模式切换为 STRICT。STRICT工作负载仅接收双向 TLS 流量。DISABLE禁用双向 TLS。从安全角度来看除非提供自己的安全解决方案否则请勿使用此模式。 这个对等认证策略将工作负载配置为仅接受 mTLS 加密的请求。由于未对 selector 字段指定值因此该策略适用于网格中的所有工作负载。 直接应用上面这个对等认证策略后我们再次发送请求来进行测试 [rootmaster1 istio-1.19.3]#kubectl apply -f peer-strict-global.yaml peerauthentication.security.istio.io/default created [rootmaster1 istio-1.19.3]#kubectl get PeerAuthentication -nistio-system NAME MODE AGE default STRICT 14s$ for from in foo bar legacy; do for to in foo bar legacy; do kubectl exec $(kubectl get pod -l appsleep -n ${from} -o jsonpath{.items..metadata.name}) -c sleep -n ${from} -- curl -s 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 的请求都失败了其他依然是成功的这是因为我们现在配置了 STRICT 严格要求使用 mTLS由于 sleep.legacy 没有 Envoy Sidecar所以无法满足这一要求所以要访问网格内部的工作负载是不被允许的。**那为什么可以访问 httpbin.legacy 呢**这是因为我们在 legacy 命名空间下的 httpbin 服务没有 Envoy Sidecar所以它不会被 Istio 管理也就不会被强制要求使用 mTLS 了所以我们可以直接访问它。 c.命名空间级别策略 实战对等认证(命名空间级别策略)-2023.11.24(测速成功) 实验环境 k8s v1.27.6containerd://1.6.20cniflannel:v0.22.2 istio v1.19.3(--set profiledemo)实验软件 链接https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd7yqb 提取码7yqb 2023.11.5-实战BookInfo 示例应用-2023.11.5(测试成功) 上面我们是在根命名空间istiod 所在的命名空间下配置的对等认证策略这样会影响到整个网格如果我们只想对某个命名空间下的服务进行配置那么我们可以使用命名空间级别的对等认证策略该策略的规范与整个网格级别的规范相同但是可以在 metadata 字段指定具体的命名空间的名称。比如我们要在 foo 命名空间上启用严格的双向 TLS 对等策略可以创建如下所示的资源对象 #peer-strict-ns.yaml apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata:name: defaultnamespace: foo # 命名空间级别 spec:mtls:mode: STRICT直接应用上面的资源对象然后再次发送请求来进行测试 # 首先删除上面创建的全局对等认证策略 [rootmaster1 istio-1.19.3]#kubectl delete -f peer-strict-global.yaml #部署 [rootmaster1 istio-1.19.3]#kubectl apply -f peer-strict-ns.yaml$ for from in foo bar legacy; do for to in foo bar legacy; do kubectl exec $(kubectl get pod -l appsleep -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由于这些策略只应用于命名空间 foo 中的服务正常我们会看到只有从没有 Sidecar 的客户端sleep.legacy到有 Sidecar 的客户端httpbin.foo的请求会失败其余都是成功的。 测试结束。 d.为每个工作负载启用双向 TLS 实战对等认证(为每个工作负载启用双向 TLS)-2023.11.24(测速成功) 实验环境 k8s v1.27.6containerd://1.6.20cniflannel:v0.22.2 istio v1.19.3(--set profiledemo)实验软件 链接https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd7yqb 提取码7yqb 2023.11.5-实战BookInfo 示例应用-2023.11.5(测试成功) 要为特定工作负载设置对等认证策略我们就必须配置 selector 字段指定与所需工作负载匹配的标签。比如我们只想要为 httpbin.bar 服务启用严格模式的 mTLS则可以创建如下所示的资源对象 #peer-strict-pod.yaml apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata:name: httpbinnamespace: bar spec:selector:matchLabels:app: httpbin # 匹配 httpbin 应用的标签mtls:mode: STRICT上面的资源对象将为 bar 命名空间中的 httpbin 应用启用严格模式的 mTLS其他工作负载不受影响。直接应用上面的资源对象然后再次发送请求来进行测试 #部署 [rootmaster1 istio-1.19.3]#kubectl apply -f peer-strict-pod.yaml$ for from in foo bar legacy; do for to in foo bar legacy; do kubectl exec $(kubectl get pod -l appsleep -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.bar 的请求因为同样的原因失败。 测试结束。 为每个端口配置不同的对等认证策略 实战对等认证(为每个端口配置不同的对等认证策略)-2023.11.24(测速成功) 实验环境 k8s v1.27.6containerd://1.6.20cniflannel:v0.22.2 istio v1.19.3(--set profiledemo)实验软件 链接https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd7yqb 提取码7yqb 2023.11.5-实战BookInfo 示例应用-2023.11.5(测试成功) 除此之外我们还可以为每个端口配置不同的对等认证策略例如以下对等认证策略要求在除 80 端口以外的所有端口上都使用双向 TLS #peer-strict-pod-port.yaml apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata:name: httpbinnamespace: bar spec:selector:matchLabels:app: httpbinmtls:mode: STRICTportLevelMtls:80:mode: DISABLE上面的资源对象中我们配置了一个 portLevelMtls 字段该字段用于配置端口级别的对等认证策略这里我们配置了 80 端口的对等认证策略为 DISABLE即禁用双向 TLS其他端口的对等认证策略为 STRICT即启用双向 TLS也就是说我们只允许 httpbin 应用的 80 端口接收明文流量其他端口都必须使用双向 TLS。 直接应用上面的资源对象然后再次发送请求来进行测试 #[rootmaster1 istio-1.19.3]#kubectl apply -f peer-strict-pod-port.yaml$ for from in foo bar legacy; do for to in foo bar legacy; do kubectl exec $(kubectl get pod -l appsleep -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可以看到现在我们从 sleep.legacy 到 httpbin.bar 的请求成功了因为我们禁用了 80 端口的双向 TLS所以 sleep.legacy 可以访问到 httpbin.bar 的服务了。 测试完成后记得删除上面创建的对等认证策略 kubectl delete peerauthentication default -n foo kubectl delete peerauthentication httpbin -n bar测试结束。 2.请求认证 Istio 的请求认证用于终端用户认证以验证附加到请求的凭据。Istio 使用 JWT 验证启用请求级认证并使用自定义认证实现或任何 OpenID Connect 的认证实现来进行认证简化。 要在 Istio 中进行请求认证可以通过一个 RequestAuthentication 资源对象来进行配置如果请求包含无效的认证信息它将根据配置的认证规则拒绝该请求。不包含任何认证凭证的请求将被接受但不会有任何认证的身份。 实战请求认证-2023.11.25(测试成功) a.JWK 与 JWKS 概述 Istio 使用 JWT 对终端用户进行身份验证Istio 要求提供 JWKS 格式的信息用于 JWT 签名验证。因此这里得先介绍一下 JWK 和 JWKS。 JWK 即 JSON Web Key是 JWT 的秘钥它描述了一个加密密钥公钥或私钥的值及其各项属性。JWKS 描述一组 JWK 密钥JWKS 的 JSON 文件格式如下: { keys: [jwk-1,jwk-2,... ]}Istio 使用 JWK 描述验证 JWT 签名所需要的信息。在使用 RSA 签名算法时JWK 描述的应该是用于验证的 RSA 公钥。一个 RSA 公钥的 JWK 描述如下 {alg: RS256, # 算法「可选参数」kty: RSA, # 密钥类型use: sig, # 被用于签名「可选参数」kid: DHFxxxxx_-envvQ, # key 的唯一 idn: xAExxxxMQ, 公钥的指数(exponent)e: AQAB # 公钥的模数(modulus) }那么需要如何生成 JWK 呢我们可以使用 https://github.com/lestrrat-go/jwx 这个命令行工具这是一个用 Go 语言开发的命令行工具内置了对各种 JWx(JWT, JWK, JWA, JWS, JWE) 的支持。 我们可以使用下面的命令来安装 jwx 命令行工具: $ export GOPROXYhttps://goproxy.io #https://goproxy.io 或者 https://goproxy.cn都行的。 $ git clone https://github.com/lestrrat-go/jwx.git $ cd jwx $ make jwx go: downloading github.com/lestrrat-go/jwx/v2 v2.0.11 go: downloading github.com/urfave/cli/v2 v2.24.4 # ...... go: downloading github.com/russross/blackfriday/v2 v2.1.0 go: downloading golang.org/x/sys v0.8.0 Installed jwx in /root/go/bin/jwx注意这里是要具有Go环境的 [rootmaster1 ~]#cp /opt/goDir/bin/jwx /usr/local/bin/ [rootmaster1 ~]#cd /tmp/ [rootmaster1 tmp]#jwx NAME:jwx - Tools for various JWE/JWK/JWS/JWT operationsUSAGE:jwx [global options] command [command options] [arguments...]COMMANDS:jwa List available algorithms and typesjwe Work with JWE messagesjwk Work with JWK and JWK setsjws Work with JWS messageshelp, h Shows a list of commands or help for one commandGLOBAL OPTIONS:--help, -h show help [rootmaster1 tmp]#报错 /opt/goDir/pkg/mod/github.com/lestrrat-go/jwx/v2v2.0.11/cert/cert.go:9:2: //go:build comment without // build comment /opt/goDir/pkg/mod/github.com/lestrrat-go/jwx/v2v2.0.11/x25519/x25519.go:10:2: //go:build comment without // build comment make: *** [jwx] Error 1 /opt/goDir/pkg/mod/github.com/lestrrat-go/jwx/v2v2.0.11/cert/cert.go:9:2: //go:build comment without // build comment /opt/goDir/pkg/mod/github.com/lestrrat-go/jwx/v2v2.0.11/x25519/x25519.go:10:2: //go:build comment without // build comment make: *** [jwx] Error 1 这个错误看起来是与 Go 的构建标记build tags相关的问题。错误信息指出在两个文件cert.go 和 x25519.go的第 9 行和第 10 行有 //go:build 注释但是缺少了 // build 注释。 // build 注释是用于控制构建的指示在何种条件下构建或不构建文件。如果这些文件是条件性地构建的你需要确保这些注释的格式是正确的。 在这两个文件中你可能需要添加 // build 注释例如 go// build some_tag或者如果这些文件是通用的不受构建标记的影响你可以直接删除这些 //go:build 注释。 请注意如果你在使用某些构建工具比如 make确保你的构建脚本和构建过程正确处理了这些文件并且使用了正确的构建标记。 排查过程 感觉是自己的go版本问题…… 重新换装了go版本后果然好了 [rootmaster1 ~]#go version go version go1.17.13 linux/amd64#原来自己go版本是go1.16.2下面我们使用 jwx 命令行工具生成一个 JWK通过模板指定 kid 为 youdianzhishi-key: $ jwx jwk generate --keysize 4096 --type RSA --template {kid:youdianzhishi-key} -o rsa.jwk $ cat rsa.jwk {d: AxxxwBw6Jok,dp: j3xxxuvQ,dq: zzxxxqQ,e: AQAB,kid: youdianzhishi-key,kty: RSA,n: 5sxxxwV8,p: -yxxxQ,q: 6zkC_xxxxKw,qi: LExxxTw }然后从 rsa.jwk 中提取 JWK 公钥: $ jwx jwk fmt --public-key -o rsa-public.jwk rsa.jwk $ cat rsa-public.jwk {e: AQAB,kid: youdianzhishi-key,kty: RSA,n: 5sxxxV8 }上面生成的 JWK 其实就是 RSA 公钥私钥换了一种存储格式而已。 我们可以使用下面的命令将它们转换成 PEM 格式的公钥和私钥: $ jwx jwk fmt -I json -O pem rsa.jwk -----BEGIN PRIVATE KEY----- MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQCym3O0Ik5QGZ8i ...... -----END PRIVATE KEY-----$ jwx jwk fmt -I json -O pem rsa-public.jwk -----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsptztCJOUBmfIqSE8LR5 ...... -----END PUBLIC KEY-----接下来我们就可以使用 jwx 命令行签发 JWT Token 并验证其有效性了 jwx jws sign --key rsa.jwk --alg RS256 --header {typ:JWT} -o token.txt - EOF {iss: testingsecure.istio.io,sub: cnych001,iat: 1700648397,exp: 1700686042,name: Yang Ming } EOFjwx jws sign --key rsa.jwk --alg RS256 --header {typ:JWT} -o token.txt - EOF {iss: testingsecure.istio.io,sub: cnych001,iat: 1700858397,exp: 1700886042,name: Yang Ming } EOF[rootmaster1 istio]#date %s 1700867814然后查看生成的 Token 文件内容 $ cat token.txt eyJhbGciOiJSUzI1NiIsImtpZCI6InlvdWRpYW56aGlzaGkta2V5In0......上面生成 JWT Token 实际上是由下面的算法生成的: base64url_encode(Header) . base64url_encode(Claims) . base64url_encode(Signature)我们可以将该 Token 粘贴到 jwt.io 网站上来解析 先看一下 Headers 部分包含了一些元数据: alg: 所使用的签名算法这里是 RSA256kid: JWK 的 kid 然后是 Payload(Claims) 部分payload 包含了这个 token 的数据信息JWT 标准规定了一些字段另外还可以加入一些承载额外信息的字段。 iss: issuertoken 是谁签发的sub: token 的主体信息一般设置为 token 代表用户身份的唯一 id 或唯一用户名exp: token 过期时间Unix 时间戳格式iat: token 创建时间 Unix 时间戳格式 最后看一下签名 Signature 信息签名是基于 JSON Web Signature (JWS) 标准来生成的签名主要用于验证 token 是否有效是否被篡改。签名支持很多种算法这里使用的是 RSASHA256具体的签名算法如下: RSASHA256(base64UrlEncode(header) . base64UrlEncode(payload),rsa-public-key,rsa-private-key最后可以使用 RSA Public Key 验证 JWT Token 的有效性: $ jwx jws verify --alg RS256 --key rsa-public.jwk token.txt {iss: testingsecure.istio.io,sub: cnych001,iat: 1700648397,exp: 1700656042,name: Yang Ming }b.配置 JWT 终端用户认证 上面我们了解了 JWT、JWK、JWKS 这些概念接下来我们来配置 Istio 的认证策略使用我们自己创建的 JWKS。 为了方便访问我们这里通过 Ingress 网关来暴露 httpbin.foo 服务为其创建一个 Gateway 对象 [rootmaster1 ~]#cd istio-1.19.3/ [rootmaster1 istio-1.19.3]#kubectl apply -f samples/httpbin/httpbin-gateway.yaml -n foo可以通过如下命令获取 HTTP 的访问端口 export INGRESS_PORT$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath{.spec.ports[?(.namehttp2)].nodePort})然后获取集群中任意一个节点的 IP 地址 export INGRESS_HOST$(kubectl get po -l istioingressgateway -n istio-system -o jsonpath{.items[0].status.hostIP})然后可以通过下面的命令来测试 httpbin.foo 服务是否可以正常访问 [rootmaster1 istio-1.19.3]#curl $INGRESS_HOST:$INGRESS_PORT/headers -s -o /dev/null -w %{http_code}\n 200如果上面命令返回 200则表示 httpbin.foo 服务可以正常访问。 接下来我们就可以添加一个请求认证策略对象该策略要求 Ingress 网关指定终端用户的 JWT。 #jwt-examplt.yaml apiVersion: security.istio.io/v1 kind: RequestAuthentication metadata:name: jwt-examplenamespace: istio-system spec:selector:matchLabels:istio: ingressgateway #匹配我们的入口网关jwtRules:- issuer: testingsecure.istio.io # 签发者需要和 JWT payload 中的 iss 属性完全一致。# forwardOriginalToken: truejwks: |{keys: [{e: AQAB,kid: youdianzhishi-key,kty: RSA,n: 5sbkUCkQDuM3hiw9UTxmxO2wUYOT69IZje7M6O_R-ApJ3KkrhQS1C2SJelBTLgbaWhAsO4jBYOmFfWGLBA-XxrhoB9KxWCGA4EXf6fukp0ljGTYE6Th6r393jIJGDFUt8vQCjj5ivmBAQHLjwmnWiG6I93mrTQhoNHQWAde21O7yYNpg6fvjVJgRFqeAtpieA-5f2sQ8fBkefM0RFgQTqWPGfLHse5nqRWY4hG_gb23GzCo_Ti2h9wJZNuTfdK8hitahOq3eLlDVVvCu8hx-8BEs5APCj54gtqePswHeRXZi_03ccNii5CnW7Y1rHiL8LHKNHhY5tD2iZByh4YrnhkUWD-CXNqyUKx90de0R9H1ON6pqsmdEx4iAMx2xvnZ0S9NbKlk3glw_AvudjJUHa41xx7qy9OZ7QV6cB_ntwLtw513lk5Tfm-RDlVgyU-EO2jKXbOeiDpnb8kgRNBMKDqY9mgLfISW54N-LBjyVwVVHOvICWo0oPJypRgPRWD8f25wHqzjlsB8nIqJkj_e9p2c5WnAGiZWuZjm6t94IfFq9lWYUsSn-JtJvh3ATsv7ptDKFz2Ko82r1uD3446mr4I0J56C-7WOHGchlSOrDWKErwkIGxyrQ_3GEkUhkSxfArAv0bajmcMCu1_j8Eekqk7Fnm5QqytCFmFevzIJkwV8}]}在上面的资源对象中我们通过 selector 匹配了 istio-ingressgateway 服务因为我们要为 Ingress 网关添加请求认证具体的请求认证规则通过 jwtRules 来进行配置这里我们配置了一个 issuer 字段该字段用于指定 JWT 的 Issuer 发行人然后配置了一个 jwks 字段该字段用于指定 JWT 的公钥集数据我们也可以通过 jwksUri 来指向一个公钥集地址。对同一个 issuersjwt 签发者可以设置多个公钥以实现 JWT 签名密钥的轮转。JWT 的验证规则是 JWT 的 payload 中有 issuer 属性首先通过 issuer 匹配到对应的 istio 中配置的 jwks。JWT 的 header 中有 kid 属性第二步在 jwks 的公钥列表中中找到 kid 相同的公钥。使用找到的公钥进行 JWT 签名验证。 配置中的 spec.selector 可以省略这样会直接在整个命名空间中生效比如在 istio-system 命名空间该配置将在全集群的所有 sidecar/ingressgateway 上生效 默认情况下Istio 在完成了身份验证之后会去掉 Authorization 请求头再进行转发。这将导致我们的后端服务获取不到对应的 Payload无法判断终端用户的身份。因此我们需要启用 Istio 的 Authorization 请求头的转发功能只需要在上面的资源对象中添加一个 forwardOriginalToken: true 字段即可。 直接应用上面的资源对象然后再次发送请求来进行测试 #kubectl apply -f jwt-example.yaml[rootmaster1 istio]#curl $INGRESS_HOST:$INGRESS_PORT/headers -s -o /dev/null -w %{http_code}\n 200可以看到现在依然可以正常访问但是如果我们请求的时候带上一个无效的 JWT Token则会返回 401 错误 [rootmaster1 istio]#curl --header Authorization: Bearer abcdef $INGRESS_HOST:$INGRESS_PORT/headers -s -o /dev/null -w %{http_code}\n 401 要想正常访问我们需要使用上面生成的 JWT Token 来进行访问 [rootmaster1 istio]#TOKEN$(cat token.txt) [rootmaster1 istio]#curl --header Authorization: Bearer $TOKEN $INGRESS_HOST:$INGRESS_PORT/headers -s -o /dev/null -w %{http_code}\n 200可以看到就可以正常访问了。 c.设置强制认证规则 从上面的测试可以看出 Istio 的 JWT 验证规则默认情况下会直接忽略不带 Authorization 请求头即 JWT的流量因此这类流量能直接进入网格内部。通常这是没问题的因为没有 Authorization 的流量即使进入到内部也会因为无法通过 payload 判别身份而被拒绝操作。但是如果我们需要禁止不带 JWT 的流量那么可以通过一个 AuthorizationPolicy 对象来进行配置了。 比如拒绝任何 JWT 无效的请求则可以创建如下的资源对象 #ap.yaml apiVersion: security.istio.io/v1 kind: AuthorizationPolicy metadata:name: deny-requests-without-authorizationnamespace: istio-system spec:selector:matchLabels:istio: ingressgatewayaction: DENY # 拒绝rules:- from:- source:notRequestPrincipals: [*] # 不存在任何请求身份Principal的 requests上面的资源对象中我们配置的 action: DENY 表示拒绝然后通过 rules 字段来配置拒绝的规则这里我们配置了一个 from 字段该字段用于指定请求的来源这里我们配置了一个 notRequestPrincipals 字段该字段用于指定请求的身份这里我们配置为 *表示任何请求身份都不允许。 应用上面的资源对象后重新发送没有令牌的请求请求失败并返回错误码 403 #kubectl apply -f ap.yaml[rootmaster1 istio]#curl $INGRESS_HOST:$INGRESS_PORT/headers -s -o /dev/null -w %{http_code}\n 403如果仅希望强制要求对部分 path 的请求必须带有 Authorization Header可以这样设置 apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata:name: deny-requests-without-authorizationnamespace: istio-system spec:selector:matchLabels:istio: ingressgatewayaction: DENY # 拒绝rules:- from:- source:notRequestPrincipals: [*] # 不存在任何请求身份的 requests# 仅强制要求如下 host/path 相关的请求必须带上 JWT tokento:- operation:hosts: [another-host.com]paths: [/headers]需要注意的是 RequestsAuthentication 和 AuthorizationPolicy 这两个对象返回的错误码是不同的 RequestsAuthentication 验证失败的请求Istio 会返回 401 状态码。AuthorizationPolicy 验证失败的请求Istio 会返回 403 状态码。 最后记得删除刚创建的资源 测试结束。 到这里我们就实现了对 JWT 的验证当然除了验证之外我们还需要授权这个我们在下面的章节中来实现。 关于我 我的博客主旨 排版美观语言精炼文档即手册步骤明细拒绝埋坑提供源码本人实战文档都是亲测成功的各位小伙伴在实际操作过程中如有什么疑问可随时联系本人帮您解决问题让我们一起进步 微信二维码 x2675263825 舍得 qq2675263825。 微信公众号 《云原生架构师实战》 个人博客站点 http://onedayxyy.cn/ 语雀 https://www.yuque.com/xyy-onlyone csdn https://blog.csdn.net/weixin_39246554?spm1010.2135.3001.5421 知乎 https://www.zhihu.com/people/foryouone 最后 好了关于本次就到这里了感谢大家阅读最后祝大家生活快乐每天都过的有意义哦我们下期见

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/86269.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电商平台网站模板prizm viewer wordpress

Java"对象序列化":是指将实现了Serializable接口的对象转换成一组byte,日后要用这个对象时候,可以根据byte数据恢复出来,并据此重新构建那个对象。 优点: 1、JavaBean类基本都要求实现了Serializable接口&…

大理建设学校官方网站网站中加入地图

--注意:因使用了sys.wait()所有api需要在协程中使用 -- 用法实例 PROJECT "ESP32C3_TM1650" VERSION "1.0.0" _G.sys require("sys") local tm1650 require "tm1650"-- 拆分整数,并把最低位数存放在数组最大索引处 loc…

正规网站建设找哪家做网站刷东西

背景 在flink中对两个流进行connect之后进行出处理的场景很常见,我们本文就以书中的一个例子为例说明下实现一个CoProcessFunction的一些要点 实现CoProcessFunction的一些要点 这个例子举例的是当收到某个传感器放行的控制消息时,从传感器传来的温度…

网站快速排名案例微博评论箱 wordpress

经典网站: Stack Overflow:作为全球最大的程序员问答社区,Stack Overflow 汇聚了大量的编程问题和解答,为程序员提供了极大的帮助。GitHub:全球最大的开源代码托管平台,程序员可以在上面共享自己的项目代码…

天津做网站哪个公司好大连开发区人才网

第一题: 输出月份英文名 设计思路: 1:看题目:主函数与函数声明,知道它要你干什么2:理解与分析:在main中,给你一个月份数字n,要求你通过调用函数char *getmonth,来判断:若…

什么叫网站开发网页视频下载器app免费

简介: 本届大会以“前沿 探索 想象力”为主题,与业界同仁、合作伙伴共同打造一场数字时代的云上相聚。其中,边缘计算技术领域因5G快速发展而备受关注,阿里云边缘云专场吸引了数百位参会嘉宾驻足。 于10月21日上午举办的“边缘云应…

深圳龙华建网站公司wordpress 注册用户列表

有没有一起拼用银行卡的,取钱的时候我用,存钱的时候你用 1、相同的树 难度等级:⭐ 直达链接:相同的树 2、单值二叉树 难度等级:⭐ 直达链接:单值二叉树 3、对称二叉树 难度等级:⭐⭐ 直达…

制作论坛类网站模板洛阳网站优化

1. Spring 是如何解决循环依赖的? Spring 通过一系列复杂的机制来解决循环依赖问题,特别是在单例作用域的 Bean 之间。以下是一些关键点和 Spring 如何处理它们: 构造函数循环依赖: Spring 容器无法解决构造函数注入导致的循环依赖。这是因…

做网站泊头net网站开发是什么

目录 &#x1f4a1;题目描述 &#x1f4a1;双指针解法 &#x1f4a1;单调栈解法 &#x1f4a1;题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 提示&#xff1a; n height.length1 < n…

网站建设的成本主要有哪几项襄阳专业网站建设公司

关于标准帧和扩展帧的区别 提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、扩展帧和标准帧的区别1.引入库 总结 前言 最近看关于DBC的报文解析&#xff0c;关于标准真和扩展帧有了更为明确的界定&#xf…

网站开发时间安排全球包装设计网

云栖号资讯&#xff1a;【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01; 所有开发人员都认为自己写的代码完全能让人看懂&#xff0c;然而&#xff0c;他们却无法解密彼此的代码(更不用说维护代码了)…

网站功能插件ui界面设计软件

一. dex文件头(1) magic value在DexFile.c dexFileParse函数中 会先检查magic opt啥是magic opt呢? 我们刚刚从cache目录拷贝出来的那个前面的dey 036就是magic opt在源码中会先解析magic opt,然后重设dexfile指针重设magic opt指针后开始解析magic value这 8 个 字节一般是…

seo站长助手免费做效果图的网站

1 概述 同时聚合两条3GPP接入链路&#xff0c;其中一条为非地面网络&#xff0c;可以提供以下5G业务使能&#xff0c;尤其适用于带宽有限或接入链路不可靠的服务不足地区:   -扩展流动宽频   -超可靠的服务通信 如技术报告38.821所述&#xff0c;若干服务场景(例如在偏远地…

centos安装 wordpress环境网站速度优化方案

判断题 1. 三方组件是开发者在系统能力的基础上进行了一层具体功能的封装&#xff0c;对其能力进行拓展的工具 正确(True) 回答正确 2. 可以通过ohpm uninstall 指令下载指定的三方库 错误(False) 回答正确 3. lottie使用loadAnimation方法加载动画。 正确(True) 回答正…

吉林省建设厅网站评职称系统做网站比较好的

Redis代替session 实现登录流程 如果使用String&#xff0c;他的value&#xff0c;用多占用一点空间&#xff0c;如果使用哈希&#xff0c;则他的value中只会存储他数据本身&#xff0c;如果不是特别在意内存&#xff0c;其实使用String就可以 设计key的具体细节 在设计这个k…

工程建设指挥部网站小程序从哪里登录

上次已将ffmpeg的动态库编译出来了&#xff0c;并且使用了ffmpeg的转码功能&#xff0c;成功将mp4格式视频转化为yuv视频&#xff0c;这篇文章基于上次测试的demo&#xff0c;使用surfaceview显示解码完成的像素数据 布局设置和权限添加 布局 <FrameLayout xmlns:android&qu…

郑州个人网站制作公司做的比较好的设计公司网站

随着科技进步&#xff0c;人类对大脑的认识不断深入。2004年脑的大尺度网络论述初步形成&#xff0c;2005年脑连接组学的概念首次提出&#xff0c;到2017年Sporns等在Nature neuroscience撰文系统论述&#xff0c;并提出了Network neuroscience的概念。与此同时&#xff0c;欧美…

服装企业营销网站建设养老保险怎么买最划算

stl格式&#xff0c;一般是用来3D打印用的文件&#xff0c;这种模型一般很小&#xff0c;经常做来做一些DIY的配件&#xff0c;如下图&#xff0c;一共有七八个模型&#xff0c;3D打印机把每个模型实体打出来后&#xff0c;就可以给小朋友组装当智益玩具玩了&#xff0c;我们把…

对于新公司如何让其做网站推广拓者设计吧邀请码怎么弄

今天在学习window编程方面的内容时&#xff0c;我想要修改一个窗口的标题&#xff0c;这个标题的内容是窗口的高度&#xff0c;这就遇到一个问题&#xff0c;设置标题的方法是SetWindowText&#xff0c;其第二个形参是LPCWSTR类型&#xff0c;怎么把内容显示到窗口标题栏上呢&a…

免费发外链的网站网站建设用哪个

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. DQL1.1 基本语法1.2 基础查询1.3 条件查询1.3 聚合函数 &#x1f324;️ 全篇…