当前位置: 首页 > news >正文

K8s in Action 阅读笔记——【12】Securing the Kubernetes API server

K8s in Action 阅读笔记——【12】Securing the Kubernetes API server

12.1 Understanding authentication

在上一章中,我们提到API服务器可以配置一个或多个认证插件(授权插件也是同样的情况)。当API服务器接收到一个请求时,它会通过认证插件列表,以便每个认证插件可以检查请求并尝试确定谁在发送请求。第一个可以从请求中提取这些信息的插件会把用户名、用户ID和客户端所属的组返回给API服务器核心。API服务器会停止调用其余的认证插件,并继续进行授权阶段。

有多个认证插件可用。它们使用以下方法获取客户端的身份:

  • 从客户端证书中
  • 从传递在HTTP头中的认证令牌中
  • 基本HTTP认证
  • 其他方式。

启动API服务器时,可以通过命令行选项启用认证插件。

12.1.1 Users and groups

一个认证插件返回已验证用户的用户名和所属组。Kubernetes不会在任何地方存储此信息;它仅用于验证用户是否被授权执行某个操作。

用户

Kubernetes区分两种连接到API服务器的客户端:实际的人类用户和每个Pod内运行的应用程序。

这两种类型的客户端都使用上述身份验证插件进行身份验证。用户应由外部系统(例如单点登录(SSO)系统)进行管理,但Pod使用称为ServiceAccount的机制,它们作为ServiceAccount资源在集群中创建和存储。相反,没有资源代表用户帐户,这意味着你不能通过API服务器创建、更新或删除用户

人类用户和ServiceAccounts都可以属于一个或多个组。我们已经说过,身份验证插件返回用户名和用户ID以及组。组用于一次授予权限给多个用户,而不是单独授予个别用户

插件返回的组只是字符串,表示任意组名称,但内置的一些组则具有特殊含义:

  • system:unauthenticated:用于没有身份验证插件可以对客户端进行身份验证的请求;
  • system:authenticated:自动分配给已经成功通过身份验证的用户;
  • system:serviceaccounts:包含系统中的所有ServiceAccounts;
  • system:serviceaccounts:<namespace>:包括特定命名空间中的所有ServiceAccounts。

12.1.2 Introducing ServiceAccounts

你已经学会了API服务器要求客户端在允许在服务器上执行操作之前进行身份验证。你已经看到了Pod如何通过发送文件/var/run/secrets/kubernetes.io/serviceaccount/token的内容进行身份验证,该文件通过一个secret卷被挂载到每个容器的文件系统中。

但是这个文件到底表示什么?每个Pod都与ServiceAccount相关联,该ServiceAccount表示在Pod中运行的应用程序的身份。token文件保存ServiceAccount的身份验证令牌。当应用程序使用此令牌连接到API服务器时,身份验证插件对ServiceAccount进行身份验证,并将ServiceAccount的用户名传递回API服务器。ServiceAccount的用户名格式如下:

system:serviceaccount:<namespace>:<service account name>

API服务器将此用户名传递给已配置的授权插件,以确定应用程序正在尝试执行的操作是否允许由ServiceAccount执行。

ServiceAccounts仅仅是Pod内运行的应用程序与API服务器进行身份验证的一种方法。如先前提到的,应用程序通过在请求中传递ServiceAccount的令牌来进行身份验证。

ServiceAccount资源

ServiceAccounts和Pods、Secrets、ConfigMaps等一样,是资源,并且仅限于单个命名空间。每个命名空间都会自动创建一个默认的ServiceAccount。可以像处理其他资源一样列出ServiceAccounts:

$ kubectl get sa
NAME      SECRETS   AGE
default   1         24d

正如所看到的,当前命名空间仅包含默认的ServiceAccount。如果需要,可以添加其他ServiceAccounts。每个Pod都与恰好一个ServiceAccount相关联,但是多个Pod可以使用同一个ServiceAccount。如图12.1,一个Pod只能使用来自同一个命名空间的ServiceAccount。

image-20230606211311754

理解ServiceAccounts如何与授权相关联

可以通过在Pod配置文件中指定帐户名称来分配ServiceAccount给Pod。如果你没有明确指定,Pod将使用命名空间中的默认ServiceAccount。

通过将不同的ServiceAccount分配给Pod,你可以控制每个Pod可以访问哪些资源。当API服务器接收带有身份验证令牌的请求时,服务器使用令牌对发送请求的客户端进行身份验证,然后确定相关的ServiceAccount是否允许执行请求的操作。API服务器从集群管理员配置的全局授权插件中获取此信息。可用的授权插件之一是基于角色的访问控制(RBAC)插件,稍后将在本章中讨论。

12.1.3 Creating ServiceAccounts

每个命名空间都包含自己的默认ServiceAccount,但如果需要,可以创建额外的ServiceAccount。但是,为什么要费心创建ServiceAccount,而不是为所有Pod使用默认的ServiceAccount呢?

显而易见的原因是集群安全性。不需要读取任何集群元数据的Pod应在受限帐户下运行,该帐户不允许它们检索或修改在集群中部署的任何资源。需要检索资源元数据的Pod应在只允许读取这些对象元数据的ServiceAccount下运行,而需要修改这些对象的Pod应在允许修改API对象的ServiceAccount下运行。

创建ServiceAccount

通过如下命令创建一个在默认命名空间中的ServiceAccount:

$ kubectl create serviceaccount foo
serviceaccount/foo created

查看其具体信息:

$ kubectl describe sa foo
Name:                foo
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none> # 将自动添加到所有使用此ServiceAccount的Pod中。
Mountable secrets:   foo-token-5pmpn # 如果强制执行可挂载Secrets,则使用此ServiceAccount的Pod只能挂载这些Secrets
Tokens:              foo-token-5pmpn # 身份验证令牌。
Events:              <none>

使用kubectl describe secret foo-token-5pmpn查看该Secret的数据,将看到它包含与默认ServiceAccount的令牌相同的项(CA证书、命名空间和令牌),如下所示:

$ kubectl describe secret foo-token-5pmpn
Name:         foo-token-5pmpn
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: fookubernetes.io/service-account.uid: 4a83e969-4006-490a-8823-acc909d7c931Type:  kubernetes.io/service-account-tokenData
====
ca.crt:     1066 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6ImhwNkxjWFIzSC1KSHNNZ0VaN09YWHdGY1ItYlh4YXNvR3Z2c1NfRmd3encifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImZvby10b2tlbi01cG1wbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJmb28iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI0YTgzZTk2OS00MDA2LTQ5MGEtODgyMy1hY2M5MDlkN2M5MzEiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpmb28ifQ.bHC3n4QJtG_qpa0jKTgTvAmm107-1mrx4d5bnGeCYYt8HYUuBQIVjroKxmqL4utrZ9j5208D6MY3TlkRccHM7cjMD1BqxIdZVUiFALiuIUEEzS9DqWjwTiJEgxiuxTYdOBLuxmxouTK15K2jGGJr2Egx0k4dO5KzI0IirPoq0GDAF9ceD7Bqs6y_9dx1WKAQ98pfo95Nc_JRwzpAHm1jQ2H5LzLZcEIocj_TA7scUgY4taWNMKIhmM30TVKG6PB_FgjbLH9913Q1IVyVtzmTa1QUcOmEFmNLDtsU50ikCbK7aIysS2XJtA8o5-zSpoxiF-tUFy8Dyz01HSuDXSMOuA

ServiceAccount中使用的身份验证令牌是JSON Web Tokens (JWT)令牌。

ServiceAccount的Mountable secrets

在第7章中,你学习了如何创建 Secrets 并将它们安装在 pod 内部。默认情况下,pod 可以安装它想要的任何 Secret。但是,可以配置 pod 的 ServiceAccount,只允许 pod 安装列在 ServiceAccount 上作为 mountable Secrets 的 Secrets。要启用此功能,ServiceAccount 必须包含以下注释:kubernetes.io/enforce-mountable-secrets=“true”。

如果 ServiceAccount 带有此注释,则使用它的任何 pod 只能安装 ServiceAccount 的 mountable Secrets,不能使用任何其他 Secret

ServiceAccount的Image pull secrets

ServiceAccount 还可以包含一组Image pull secrets,,它们是用于保存从私有镜像库拉取容器镜像的凭据的 Secrets

向 ServiceAccount 添加Image pull secrets 可以避免单独为每个 pod 添加 Secrets。

12.1.4 Assigning a ServiceAccount to a pod

创建使用自定义ServiceAccount的Pod

在第8章中,你部署了一个 Pod,其中包含基于 tutum/curl 镜像的容器和一个ambassador容器。你使用它来探索 API 服务器的 REST 接口。ambassador容器运行了 kubectl proxy 进程,它使用 Pod 的 ServiceAccount 令牌来验证与 API 服务器的连接。现在,你可以修改该 Pod,以便使用创建的 foo ServiceAccount。下面的示例显示了 Pod 的定义:

# curl-custom-sa.yaml
apiVersion: v1
kind: Pod
metadata:name: curl-with-ambassador
spec:serviceAccountName: foocontainers:- name: mainimage: tutum/curlcommand: ["sleep", "9999999"]- name: ambassadorimage: luksa/kubectl-proxy:1.6.2

要确认自定义ServiceAccount的令牌已安装到两个容器中,可以打印令牌的内容:

$ kubectl exec -it curl-with-ambassador  -c main --  cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6ImhwNkxjWFIzSC1KSHNNZ0VaN09YWHdGY1ItYlh4YXNvR3Z2c......

使用自定义ServiceAccount的令牌与API服务器对话

让我们看看你是否可以使用这个令牌与API服务器进行通信。 如前所述,ambassador容器在与服务器通信时使用令牌,因此你可以通过ambassador进行测试,ambassador监听localhost:8001,如下所示:

$ kubectl exec -it curl-with-ambassador  -c main curl localhost:8001/api/v1/pods
{"kind": "PodList","apiVersion": "v1","metadata": {"resourceVersion": "4385870"},"items": [{"metadata": {"name": "curl-with-ambassador",......

当你的集群没有正确的授权时,创建和使用其他ServiceAccount没有意义,因为即使是默认的ServiceAccount也允许执行任何操作。在这种情况下使用ServiceAccounts的唯一理由是通过ServiceAccount强制执行可挂载的Secrets或提供镜像拉取Secrets(如前所述)。

但是,当你使用RBAC授权插件时,创建其他ServiceAccounts几乎是必不可少的。

12.2 Securing the cluster with role-based access control

12.2.1 Introducing the RBAC authorization plugin

Kubernetes API服务器可以配置使用授权插件来检查请求操作的用户是否被允许执行该操作。因为API服务器暴露了一个REST接口,用户通过向服务器发送HTTP请求来执行操作。用户通过在请求中包含凭据(身份验证令牌、用户名和密码或客户端证书)进行身份验证。

REST客户端向表示特定REST资源的特定URL路径发送GET、POST、PUT、DELETE和其他类型的HTTP请求。在Kubernetes中,这些资源是Pod、 Service、Secrets等。以下是Kubernetes中一些操作的示例:

  • 获取Pods
  • 创建Services
  • 更新Secrets
  • 等等

这些示例中的动词(获取、创建、更新)映射到客户端执行的HTTP方法(GET、POST、PUT)(完整映射在表12.1中显示)。名词(Pods、Services、Secrets)显然映射到Kubernetes资源。

image-20230607110115431

像RBAC这样在API服务器内部运行的授权插件确定客户端是否被允许对请求的资源执行请求动作

正如其名称所示,RBAC授权插件使用用户角色作为确定用户是否可以执行操作的关键因素。一个主体(可以是人员、ServiceAccount或一组用户或ServiceAccount)与一个或多个角色相关联,每个角色被允许对某些资源执行特定的动词

如果用户拥有多个角色,则他们可以执行任何一个角色允许他们执行的操作。例如,如果用户的所有角色都不包含更新Secrets的权限,则API服务器将阻止用户对Secrets执行PUT或PATCH请求。

通过RBAC插件管理授权非常简单。所有操作都通过创建四个RBAC-specific的Kubernetes资源完成,我们将在下一节进行介绍。

12.2.2 Introducing RBAC resources

RBAC授权规则通过四个资源进行配置,可以分为两组:

  • Roles和ClusterRoles:指定可以在哪些资源上执行哪些动作。
  • RoleBindings和ClusterRoleBindings:将上述角色绑定到特定的用户、组或ServiceAccount上。Roles定义可以完成的操作,而bindings定义谁可以执行它们(如图12.2所示)。

image-20230607111438825

Role和RoleBinding是有命名空间的资源,而ClusterRole和ClusterRoleBinding是集群级别的资源(没有命名空间)。如图12.3所示。可以看出,多个RoleBindings可以存在于单个命名空间中(Roles也是如此)。同样,可以创建多个ClusterRoleBindings和ClusterRoles。图中还显示了一件事情,虽然RoleBindings有命名空间,但也可以引用没有命名空间的ClusterRoles。

image-20230607111509882

之前禁用过RBAC插件,现在重新启动一下:

$ kubectl delete clusterrolebinding permissive-binding
clusterrolebinding.rbac.authorization.k8s.io "permissive-binding" deleted

创建命名空间与运行Pod

$ kubectl create ns foo
namespace/foo created$ kubectl run test --image=luksa/kubectl-proxy -n foo
pod/test created$ kubectl create ns bar
namespace/bar created$ kubectl run test --image=luksa/kubectl-proxy -n bar
pod/test created

现在打开两个终端,并使用kubectl exec在两个Pod(每个终端一个)中运行一个shell:

$ kubectl exec -it test -n foo -- sh
/ # 

从Pod中监听Service

要验证RBAC已启用并防止Pod读取群集状态,使用curl列出foo命名空间中的Services:

/ # curl localhost:8001/api/v1/namespaces/foo/services
{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "services is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"services\" in API group \"\" in the namespace \"foo\"","reason": "Forbidden","details": {"kind": "services"},"code": 403
}

API服务器响应称,ServiceAccount不被允许在foo命名空间中列出Services,即使Pod正在该命名空间中运行。正在看到RBAC正在发挥作用。默认的ServiceAccount权限不允许列出或修改任何资源。现在,让我们学习如何允许ServiceAccount执行该操作。

12.2.3 Using Roles and RoleBindings

一个Role资源定义了可以对哪些资源执行哪些操作。以下清单定义了一个Role,允许用户获取和列出foo命名空间中的Services:

# service-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:namespace: foo # 角色是有命名空间的(如果省略命名空间,则使用当前命名空间)。name: service-reader
rules: 
- apiGroups: [""] # Service是apiGroup中的资源,该组没有名称 ,因此使用 ""verbs: ["get", "list"] # 允许获取单个服务(按名称)和列出所有服务resources: ["services"] # 此规则适用于服务(必须使用复数!)

这个Role资源将在foo命名空间中被创建。在第8章中,你学习了每个资源类型都属于一个API组,你需要在资源清单中的apiVersion字段中指定它(以及版本)。在Role定义中,你需要为每个规则中列出的资源指定apiGroup。如果你要允许访问属于不同API组的资源,则使用多个规则。

在这个例子中,你允许访问所有Service资源,但也可以通过额外的resourceNames字段指定它们的名称来限制访问特定的Service实例。

图12.4显示了该Role以及它的动作和资源,以及它将被创建在哪个命名空间中。

image-20230607113329636

创建Role

在foo命名空间下创建Role:

$ kubectl create -f service-reader.yaml -n foo
role.rbac.authorization.k8s.io/service-reader created

除了用YAML文件创建Role,同样可以用命令行来创建:

$ kubectl create role service-reader --verb=get --verb=list --resource=services -n bar
role.rbac.authorization.k8s.io/service-reader create

这两个角色将允许你在两个 Pod 中(分别在 foo 和 bar 命名空间中运行)列出 foo 和 bar 命名空间中的服务。但是创建这两个角色是不够的(你可以通过再次执行 curl 命令来检查)。你需要将每个角色绑定到其各自命名空间中的ServiceAccounts

将Role绑定到ServiceAccount

角色定义了可以执行哪些操作,但它并没有指定谁可以执行它们。要做到这一点,你必须将角色绑定到一个主体,这可以是用户、ServiceAccount或组(用户或ServiceAccount组)。

将Role绑定到主体是通过创建 RoleBinding 资源实现的。要将Role绑定到默认的 ServiceAccount,请运行以下命令:

$ kubectl create rolebinding test --role=service-reader --serviceaccount=foo:default -n foo
rolebinding.rbac.authorization.k8s.io/test created

正在创建一个 RoleBinding,将默认的 ServiceAccount 与service-reader角色绑定在 foo 命名空间中。你正在 foo 命名空间创建 RoleBinding。RoleBinding 和引用的 ServiceAccount 和 Role 如图 12.5 所示。

image-20230607152204763

要将Role绑定到用户而不是ServiceAccount,请使用 --user 参数指定用户名。要将其绑定到组,请使用 --group。

查看所创建的RoleBinding:

$ kubectl get rolebinding test -n foo -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:creationTimestamp: "2023-06-07T07:21:46Z"name: testnamespace: fooresourceVersion: "4418118"uid: 2b431c06-1f8a-4e28-820d-5ee4bf66e439
roleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: service-reader
subjects:
- kind: ServiceAccountname: defaultnamespace: foo

RoleBinding 总是引用单个角色(如 roleRef 属性所示),但可以将该Role绑定到多个主体(例如,一个或多个服务账户和任意数量的用户或组)。因为这个 RoleBinding 将角色绑定到了在 foo 命名空间下运行的 Pod 的 ServiceAccount,所以现在可以在该 Pod 中列出Service:

/ # curl localhost:8001/api/v1/namespaces/foo/services
{"kind": "ServiceList","apiVersion": "v1","metadata": {"resourceVersion": "4418540"},"items": []
}

在RoleBinding中包含来自其他命名空间的ServiceAccount

在 bar 命名空间下的 Pod 无法列出其自己命名空间中的服务,显然也无法列出 foo 命名空间中的服务。但是,你可以在 foo 命名空间中编辑你的 RoleBinding,并添加另一个 Pod 的 ServiceAccount,即使它在不同的命名空间中也可以。运行以下命令:

修改内容如下:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:creationTimestamp: "2023-06-07T07:21:46Z"name: testnamespace: fooresourceVersion: "4418118"uid: 2b431c06-1f8a-4e28-820d-5ee4bf66e439
roleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: service-reader
subjects:
- kind: ServiceAccountname: defaultnamespace: foo
- kind: ServiceAccountname: defaultnamespace: bar

现在,在 bar 命名空间中运行的 Pod 中,你也可以列出 foo 命名空间中的服务:

$ kubectl exec -it test -n bar -- sh
/ # curl localhost:8001/api/v1/namespaces/foo/services
{"kind": "ServiceList","apiVersion": "v1","metadata": {"resourceVersion": "4420883"},"items": []
}

在继续介绍 ClusterRoles 和 ClusterRoleBindings 之前,让我们总结目前你拥有的 RBAC 资源。在 foo 命名空间中,你拥有一个 RoleBinding,它引用service-reader角色(也在 foo 命名空间中),将 foo 和 bar 命名空间中的默认 ServiceAccount 绑定在一起,如图 12.6 所示。

image-20230607154350308

12.2.4 Using ClusterRoles and ClusterRoleBindings

Role和 RoleBinding 是命名空间资源,这意味着它们应用于单个命名空间中的资源,但是,正如我们所看到的,RoleBinding 也可以引用来自其他命名空间的 ServiceAccount。

除了这些命名空间资源之外,还存在两个集群级别的 RBAC 资源:ClusterRole 和 ClusterRoleBinding。它们不是命名空间资源。让我们看看为什么你需要它们。

普通的角色只允许访问与角色所在命名空间中的资源。如果想允许某人访问不同命名空间中的资源,则必须在每个命名空间中创建Role和 RoleBinding。如果想将其扩展到所有命名空间(这是集群管理员可能需要的),则需要在每个命名空间中创建相同的Role和 RoleBinding。创建附加命名空间时,则必须记住在其中也创建这两个资源。

正如你在本书中学到的那样,某些资源根本没有命名空间(这包括节点、持久卷、命名空间等)。我们还提到 API 服务器公开了一些不代表资源的 URL 路径(例如 /healthz)。普通的角色无法授予对这些资源或非资源 URL 的访问权限,但是 ClusterRoles 可以。

ClusterRole 是一个集群级别资源,用于允许访问非命名空间资源或非资源 URL,或者用作在各个命名空间内绑定的普通角色,可以避免不得不在每个命名空间中重新定义相同的角色。

允许访问集群级资源

如上所述,ClusterRole 可以用于允许访问集群级别的资源。让我们看看如何允许你的 Pod 在集群中列出 PersistentVolumes。首先,你将创建一个名为 pv-reader 的 ClusterRole:

$ kubectl create clusterrole pv-reader --verb=get,list --resource=persistentvolumes
clusterrole.rbac.authorization.k8s.io/pv-reader created

ClusterRole 的 YAML 如下所示:

$ kubectl get clusterrole pv-reader -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:creationTimestamp: "2023-06-07T07:59:02Z"name: pv-readerresourceVersion: "4422657"uid: 7c68c1d1-9fe6-41ab-95dc-442f525f09b7
rules:
- apiGroups:- ""resources:- persistentvolumesverbs:- get- list

在将此 ClusterRole 绑定到你的 Pod 的 ServiceAccount 之前,请验证该 Pod 是否可以列出 PersistentVolumes。在第一个终端中,你正在 foo 命名空间内运行 pod 中的 shell,执行以下命令:

$ kubectl exec -it test -n foo -- sh
/ # curl localhost:8001/api/v1/persistentvolumes
{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "persistentvolumes is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"persistentvolumes\" in API group \"\" at the cluster scope","reason": "Forbidden","details": {"kind": "persistentvolumes"},"code": 403
}

如预期的那样,默认 ServiceAccount 无法列出 PersistentVolumes。你需要将 ClusterRole 绑定到你的 ServiceAccount,以允许其执行此操作。ClusterRoles 可以使用常规 RoleBindings 绑定到主体,因此现在你将创建一个 RoleBinding:

$ kubectl create rolebinding pv-test --clusterrole=pv-reader --serviceaccount=foo:default -n foo
rolebinding.rbac.authorization.k8s.io/pv-test created

现在你是否可以列出 PersistentVolumes?

/ # curl localhost:8001/api/v1/persistentvolumes
{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "persistentvolumes is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"persistentvolumes\" in API group \"\" at the cluster scope","reason": "Forbidden","details": {"kind": "persistentvolumes"},"code": 403
}

问题出在哪里呢?

尽管你可以创建一个 RoleBinding,并将其引用到 ClusterRole,以使其可以访问命名空间资源,但是对于集群级别(非命名空间)资源,你不能使用相同的方法。要授予对集群级别资源的访问权限,你必须始终使用 ClusterRoleBinding

首先要清理和删除 RoleBinding:

$ kubectl delete rolebinding pv-test -n foo
rolebinding.rbac.authorization.k8s.io "pv-test" deleted

创建ClusterRoleBinding:

$ kubectl create clusterrolebinding pv-test --clusterrole=pv-reader --serviceaccount=foo:default
clusterrolebinding.rbac.authorization.k8s.io/pv-test created

正如你所看到的,你在命令中将 RoleBinding 替换为 ClusterRoleBinding,并且没有(也不需要)指定命名空间。图 12.8 显示了你现在拥有的内容。

/ # curl localhost:8001/api/v1/persistentvolumes
{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "persistentvolumes is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"persistentvolumes\" in API group \"\" at the cluster scope","reason": "Forbidden","details": {"kind": "persistentvolumes"},

必须使用 ClusterRole 和 ClusterRoleBinding 来授予对集群级别资源的访问权限。

image-20230607160521797

允许访问非资源URL

我们已经提到,API 服务器还公开了非资源 URL。对这些 URL 的访问权限也必须显式授予;否则,API 服务器将拒绝客户端的请求。通常,通过 system:discovery ClusterRole 和同名的 ClusterRoleBinding自动为你完成此操作。

查看 system:discovery ClusterRole:

$ kubectl get clusterrole system:discovery -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:annotations:rbac.authorization.kubernetes.io/autoupdate: "true"creationTimestamp: "2023-05-13T10:15:00Z"labels:kubernetes.io/bootstrapping: rbac-defaultsname: system:discoveryresourceVersion: "89"uid: 42973c1c-4ccd-44eb-a8dd-d8b07fdc76bc
rules:
- nonResourceURLs:- /api- /api/*- /apis- /apis/*- /healthz- /livez- /openapi- /openapi/*- /readyz- /version- /version/verbs:- get

你可以看到,该 ClusterRole 引用 URL 而不是资源(使用 nonResourceURLs 字段而不是 resources 字段)。verbs 字段仅允许在这些 URL 上使用 GET HTTP 方法。

对于非资源 URL,使用 post、put 和 patch 等普通 HTTP 动词,而不是 create 或 update。这些动词需要以小写指定。

与集群级别资源类似,非资源 URL 的 ClusterRoles 必须使用 ClusterRoleBinding 绑定。使用 RoleBinding 绑定它们将没有任何效果。system:discovery ClusterRole 有一个相应的 system:discovery ClusterRoleBinding,让我们查看其中的内容:

$ kubectl get clusterrolebinding system:discovery -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:annotations:rbac.authorization.kubernetes.io/autoupdate: "true"creationTimestamp: "2023-05-13T10:15:00Z"labels:kubernetes.io/bootstrapping: rbac-defaultsname: system:discoveryresourceVersion: "152"uid: e78be8f1-fdb2-43e5-87f8-b7b7d02d83d0
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: system:discovery
subjects:
- apiGroup: rbac.authorization.k8s.iokind: Groupname: system:authenticated

YAML 显示 ClusterRoleBinding 引用了 system:discovery ClusterRole,正如预期的那样。它绑定到两个组,system:authenticatedsystem:unauthenticated,这使其绑定到所有用户。这意味着每个人都可以访问 ClusterRole 中列出的 URL。

你可以通过访问 /api URL 路径来验证这一点,从 pod 内部(通过 kubectl 代理,这意味着你将作为 pod 的 ServiceAccount 身份验证)和你的本地机器,不需要指定任何身份验证令牌:

现在你已经使用 ClusterRoles 和 ClusterRoleBindings 授予了访问集群级资源和非资源 URL 的权限。现在让我们来看看 ClusterRoles 如何与命名空间 RoleBindings 一起使用,来授予 RoleBinding 命名空间中的资源的访问权限。

使用ClusterRoles 授予对特定命名空间中资源的访问权限

ClusterRoles并非总是需要与集群级别的ClusterRoleBindings绑定。它们也可以与普通的、命名空间级别的RoleBindings绑定。你已经开始查看预定义的ClusterRoles,现在让我们看看另一个名为view的ClusterRole:

kubectl get clusterrole view -o yaml
aggregationRule:clusterRoleSelectors:- matchLabels:rbac.authorization.k8s.io/aggregate-to-view: "true"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:annotations:rbac.authorization.kubernetes.io/autoupdate: "true"creationTimestamp: "2023-05-13T10:15:00Z"labels:kubernetes.io/bootstrapping: rbac-defaultsrbac.authorization.k8s.io/aggregate-to-edit: "true"name: viewresourceVersion: "33196"uid: 5133c3d9-f0df-4145-aa0b-57d5a52b8aa8
rules:
- apiGroups:- ""resources:- configmaps- endpoints- persistentvolumeclaims- persistentvolumeclaims/status- pods- replicationcontrollers- replicationcontrollers/scale- serviceaccounts- services- services/statusverbs:- get- list- watch
- apiGroups:- ""resources:- bindings- events- limitranges- namespaces/status- pods/log- pods/status- replicationcontrollers/status- resourcequotas- resourcequotas/statusverbs:- get- list- watch
- apiGroups:- ""resources:- namespacesverbs:- get- list- watch
- apiGroups:- appsresources:- controllerrevisions- daemonsets- daemonsets/status- deployments- deployments/scale- deployments/status- replicasets- replicasets/scale- replicasets/status- statefulsets- statefulsets/scale- statefulsets/statusverbs:- get- list- watch
- apiGroups:- autoscalingresources:- horizontalpodautoscalers- horizontalpodautoscalers/statusverbs:- get- list- watch
- apiGroups:- batchresources:- cronjobs- cronjobs/status- jobs- jobs/statusverbs:- get- list- watch
- apiGroups:- extensionsresources:- daemonsets- daemonsets/status- deployments- deployments/scale- deployments/status- ingresses- ingresses/status- networkpolicies- replicasets- replicasets/scale- replicasets/status- replicationcontrollers/scaleverbs:- get- list- watch
- apiGroups:- policyresources:- poddisruptionbudgets- poddisruptionbudgets/statusverbs:- get- list- watch
- apiGroups:- networking.k8s.ioresources:- ingresses- ingresses/status- networkpoliciesverbs:- get- list- watch
- apiGroups:- metrics.k8s.ioresources:- pods- nodesverbs:- get- list- watch

这个ClusterRole有许多规则。列表中只显示了第一个规则。该规则允许获取、列出和监视像ConfigMaps、Endpoints、PersistentVolumeClaims等资源。这个ClusterRole到底是做什么的呢?

这取决于它是与ClusterRoleBinding还是RoleBinding绑定在一起(它可以与任何一个绑定)。如果你创建一个ClusterRoleBinding并在其中引用ClusterRole,那么绑定中列出的主体可以查看所有命名空间中指定的资源。另一方面,如果你创建一个RoleBinding,那么在绑定中列出的主体只能查看RoleBinding所在命名空间中的资源。现在你将尝试这两个选项。

首先,让我们看看在任何绑定存在之前会发生什么:

$ kubectl exec -it test -n foo -- sh
/ # curl localhost:8001/api/v1/pods
{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "pods is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"pods\" in API group \"\" at the cluster scope","reason": "Forbidden","details": {"kind": "pods"},"code": 403
}/ # curl localhost:8001/api/v1/namespaces/foo/pods
{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "pods is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"pods\" in API group \"\" in the namespace \"foo\"","reason": "Forbidden","details": {"kind": "pods"},"code": 403
}

通过第一个命令,你试图在所有命名空间中列出Pods。通过第二个命令,你试图列出foo命名空间中的Pods。但服务器不允许你执行这两个操作。

现在,让我们看看当你创建了一个ClusterRoleBinding并将其绑定到Pod的ServiceAccount时会发生什么:

$ kubectl create clusterrolebinding view-test --clusterrole=view --serviceaccount=foo:default
clusterrolebinding.rbac.authorization.k8s.io/view-test created

现在,Pod是否可以列出foo命名空间中的Pods?

/ # curl localhost:8001/api/v1/namespaces/foo/pods
{"kind": "PodList","apiVersion": "v1","metadata": {"resourceVersion": "4429194"},"items": [......

可以!因为你创建了一个ClusterRoleBinding,它适用于所有命名空间。foo命名空间中的Pod也可以列出bar命名空间中的Pod:

好的,Pod被允许在一个不同的命名空间中列出Pod。它也可以通过访问/api/v1/pods URL路径来检索所有命名空间中的Pods

/ # curl localhost:8001/api/v1/namespaces/bar/pods
{"kind": "PodList","apiVersion": "v1","metadata": {"resourceVersion": "4429300"},"items": [{"metadata": {"name": "test","namespace": "bar","uid": "dabbd578-4baf-470f-bfd8-c11e0555c073",

正如预期的那样,Pod可以获取集群中所有Pods的列表。综上所述,将一个参考命名空间资源的ClusterRole与ClusterRoleBinding结合起来,允许Pod在任何命名空间中访问命名空间资源,如图12.9所示。

现在,让我们看看如果你用RoleBinding替换ClusterRoleBinding会发生什么。首先,删除ClusterRoleBinding:

$ kubectl delete clusterrolebinding view-test
clusterrolebinding.rbac.authorization.k8s.io "view-test" deleted

然后,创建一个RoleBinding。由于RoleBinding是命名空间级别的,所以你需要指定你想要创建它的命名空间。在foo命名空间中创建它:

$ kubectl create rolebinding view-test --clusterrole=view --serviceaccount=foo:default -n foo
rolebinding.rbac.authorization.k8s.io/view-test created

你现在在foo命名空间中有一个RoleBinding,将该命名空间中的默认ServiceAccount与view ClusterRole绑定起来。现在,你的Pod可以访问什么?

/ # curl localhost:8001/api/v1/namespaces/foo/pods
{"kind": "PodList","apiVersion": "v1","metadata": {"resourceVersion": "4429194"},"items": [....../ # curl localhost:8001/api/v1/namespaces/bar/pods
{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "pods is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"pods\" in API group \"\" in the namespace \"bar\"","reason": "Forbidden","details": {"kind": "pods"},"code": 403
}/ # curl localhost:8001/api/v1/pods
{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "pods is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"pods\" in API group \"\" at the cluster scope","reason": "Forbidden","details": {"kind": "pods"},"code": 403
}

正如你所看到的,你的Pod可以列出foo命名空间中的Pod,但无法访问其他特定命名空间,也不能访问所有命名空间中的Pod。这在图12.10中可视化呈现。

image-20230607170211962

小总结

访问类型Role的类型Binding的类型
集群资源(如Nodes,PersistentVolumes)ClusterRoleClusterRoleBinding
无资源URL(/api,/healthz,…)ClusterRoleClusterRoleBinding
任何命名空间(以及所有命名空间)中的命名空间资源ClusterRoleClusterRoleBinding
特定命名空间中的命名空间资源(在多个命名空间中重用相同的ClusterRole)ClusterRoleRoleBinding
特定命名空间中的命名空间资源(必须在每个命名空间中定义Role)RoleRoleBinding

12.2.5 Understanding default ClusterRoles and ClusterRoleBindings

Kubernetes附带了一组默认的ClusterRoles和ClusterRoleBindings,每次API服务器启动时都会更新。这确保了所有默认的角色和绑定在你错误地删除它们或Kubernetes的新版本使用不同的群集角色和绑定配置时会重新创建。

最重要的角色是view、edit、admin和cluster-admin ClusterRoles。它们的目的是绑定到由用户定义的Pod使用的ServiceAccount。

使用view ClusterRole允许对资源进行只读访问

你已经在之前的例子中使用了默认的view ClusterRole。它允许读取命名空间中的大多数资源,但不能读取Roles、RoleBindings和Secrets。你可能会想,为什么不能读取Secrets?因为其中一个Secret可能包含权限大于view ClusterRole定义的权限的身份验证令牌,可以允许用户变成不同的用户以获取附加权限(特权升级)。

使用edit ClusterRole允许修改资源

接下来是edit ClusterRole,它允许你修改命名空间中的资源,但也允许读取和修改Secrets。然而,它不能允许查看或修改Roles或RoleBindings——同样是为了防止特权升级。

使用admin ClusterRole授予命名空间的完全控制权

admin ClusterRole授予命名空间中资源的完全控制权。具有该ClusterRole的主体可以读取和修改命名空间中的任何资源,但不能读取或修改ResourceQuotas(我们将在第14章中学习这些)和Namespace资源本身。edit ClusterRole和admin ClusterRole之间的主要区别在于能否查看和修改命名空间中的Roles和RoleBindings。

使用cluster-admin ClusterRole允许完全控制

分配cluster-admin ClusterRole给一个主体可以给予该Kubernetes集群的完全控制权。正如之前所见,admin ClusterRole不允许用户修改命名空间的ResourceQuota对象或Namespace资源本身。如果你想让一个用户可以这样做,你需要创建一个引用cluster-admin ClusterRole的RoleBinding。这会让在RoleBinding中包含的用户完全控制创建RoleBinding的命名空间的所有方面。

如果你仔细看过,你可能已经知道如何让用户完全控制集群中的所有命名空间。是的,通过在ClusterRoleBinding中引用cluster-admin ClusterRole而不是RoleBinding。

了解其他默认的ClusterRoles

默认的ClusterRoles列表包括大量以system:前缀开头的ClusterRoles,它们旨在由各种Kubernetes组件使用。其中,你会找到像system:kube-scheduler这样的角色,它显然被调度器使用,system:node,它被Kubelets使用,等等。

虽然控制器管理器是作为单个pod运行的,但在其中运行的每个控制器都可以使用单独的ClusterRole和ClusterRoleBinding(它们的前缀为system: controller😃。

每个这些系统ClusterRole都有一个匹配的ClusterRoleBinding,将其绑定到系统组件认证的用户上。例如,system:kube-scheduler ClusterRoleBinding将名称相同的ClusterRole分配给system:kube-scheduler用户,这是调度器的用户名。

12.2.6 Granting authorization permissions wisely

在一个命名空间中,默认情况下,默认的ServiceAccount除了认证用户之外,没有其他权限。因此,默认情况下,Pod甚至无法查看集群状态。由你来授予它们适当的权限来执行此操作。

显然,给所有的ServiceAccount都授予cluster-admin ClusterRole是一个糟糕的想法。确保安全的话通常最好仅授予每个人执行工作所需的权限。

为每个Pod创建特定的ServiceAccount是个好主意,然后通过RoleBinding(而不是ClusterRoleBinding,因为这会使Pod能够访问其他命名空间中的资源,这可能不是你想要的)将其与特制的Role(或ClusterRole)关联起来。

如果你的其中一个Pod(其中运行的应用程序)只需要读取Pods,而另一个则需要修改它们,则创建两个不同的ServiceAccount,并通过在Pod规格中指定serviceAccountName属性来使这些Pod使用它们。不要将两个Pod所需的所有必要权限添加到命名空间中的默认ServiceAccount中。

RBAC介绍(补充知识)

RBAC权限控制机制分析

RBAC,即基于角色的访问控制,是用户通过角色与权限进行关联,与传统的将用户与权限直接关联不同,RBAC的本质是单纯地用户和权限进行解耦,将用户与角色、角色与权限关联。这样方便对拥有相同特征的多个用户的权限进行管理,也符合系统低耦合度的要求。

image-20211110193700073

RBAC将权限分析的过程抽象为判断某个角色(role)对某个对象(object)进行怎样的操作(action),引入对象和操作以后,上图的模型也就构成了RBAC0基础模型

image-20211110193932346

而根据控制对象的不同,控制粒度也会不同,在一般的开发中,主要有对页面、菜单和控件的控制。

  1. 页面控制:每个用户登录以后根据其分配到的角色权限跳转到不同的主页面,此时软件的整个页面是与角色相联系的,若有n个角色,就会对应n个主页面。显然,这种控制粒度是较粗的,即便不同的角色有一些共同的页面元素也需要创建一个新的页面,这会造成大量代码的复制粘贴,十分不推荐使用。

  2. 菜单控制:每个用户登录以后可以跳转到相同的主页面,这时候可以根据其拥有的菜单控制权限显示菜单,没有权限的菜单对用户是不可见的**,**从而呈现不同的页面效果。此时的控制粒度居中,可以提高对代码的重用率。

  3. **控件控制:**这里的控制对象可以是页面中的控件,如按钮,输入框等,可以与监听事件机制相结合,实现对控件操作的权限控制。如判断用户是否可以点击相应的功能按钮、是否可以对输入框进行输入等。此时实现了细粒度的权限控制,使系统安全性更高。

    image-20211110193949960

RBAC模型簇

RBAC是一个模型簇,最被公认的使RBAC96模型簇,包括RBAC0、RBAC1、RBAC2、RBAC3。RBAC0在上文已经分析解释,下面只说明剩余的三种模型。

  1. RBAC1:也称为角色分级模型**,**引入了角色间的继承关系,也就是说,角色上有了上下级的区别。父角色拥有其子角色所有的许可。例如对于公司的部门主管角色,其可以具有子角色:部门副主管、部门小组长,父角色拥有子角色的所有权限,同时具有子角色不具有的一些权限。

image-20211110194000847

  1. RBAC2:也称为限制模型,RBAC2也是建立的RBAC0的基础之上的,在RBAC0基础上引入了约束的概念,主要引入了静态职责分离SSD和动态职责分离DSD。SSD是用户和角色的指派阶段加入的,主要是对用户和角色有如下约束:

    a、互斥角色:同一个用户在两个互斥角色中只能选择一个

    b、基数约束:一个用户拥有的角色是有限的,一个角色拥有的许可也是有限的

    c、先决条件约束:用户想要获得高级角色,首先必须拥有低级角色

    DSD是会话和角色之间的约束,可以动态的约束用户拥有的角色,如一个用户可 以拥有两个角色,但是运行时只能激活一个角色。

image-20211110194213448

  1. RBAC3:RBAC3,它是RBAC1与RBAC2合集,所以RBAC3是既有角色分层又有约束的一种模型。

image-20211110194253400

相关文章:

K8s in Action 阅读笔记——【12】Securing the Kubernetes API server

K8s in Action 阅读笔记——【12】Securing the Kubernetes API server 12.1 Understanding authentication 在上一章中&#xff0c;我们提到API服务器可以配置一个或多个认证插件&#xff08;授权插件也是同样的情况&#xff09;。当API服务器接收到一个请求时&#xff0c;它…...

爆肝整理,3个月从功能进阶自动化测试,一跃成测试卷王...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 首先先了解自动化…...

人生这场概率游戏,怎么玩

只会标准答案&#xff0c;是不可救药的愚蠢 那么为了便于理解&#xff0c;我用一些典型的案例来讲解&#xff0c;什么是概率游戏&#xff0c;以及这个游戏&#xff0c;应该怎么玩。 比如典型的相亲&#xff0c;婚恋。人生大事&#xff0c;用标准答案来说&#xff0c;你的意中人…...

Redis笔记

缓存过期时间很重要&#xff01;redis是单线程的 对于内存过多的3中方案&#xff1a; 惰性删除&#xff1a; 在定时删除的基础上&#xff0c;对于已经过期了的数据&#xff0c;redis的随机选择算法一直没有选中这个数据&#xff0c;所以导致它就一直没被删除&#xff0c;但是…...

centos 安装supervisor并运行网站

前言 之前一直用宝塔的**进程守护管理器【Supervisor】**来启动一些项目,如ThinkPHP、Hyperf的项目,或laravel的一些命令。如果不用宝塔怎么办呢? 一、简介[supervisor] [Supervisor] 是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支…...

Hadoop面试题十道

问题 1&#xff1a;Hadoop是什么&#xff1f; 答案&#xff1a;Hadoop是一个开源的分布式计算框架&#xff0c;用于处理大规模数据集的存储和处理。它基于Google的MapReduce和Google文件系统&#xff08;GFS&#xff09;的思想&#xff0c;旨在解决大数据量的处理和分析问题。…...

使用Docker-Compose对Docker容器集群快速编排

目录 一、Docker-Compose1、Docker-Compose使用场景2、Docker-Compose简介3、Docker-Compose安装部署4、YAML 文件格式及编写注意事项5、Docker Compose配置常用字段6、Docker Compose 常用命令7、Docker Compose 文件结构8、docker Compose撰写nginx 镜像9、docker Compose撰写…...

React-Redux 对Todolist修改

在单独使用redux的时候 需要手动订阅store里面 感觉特别麻烦 不错的是react有一个组件可以帮我们解决这个问题, 那就是react-redux。 react-redux提供了Provider 和 connent给我们使用。 先说一下几个重点知道的知识 Provider 就是用来提供store里面的状态 自动getState()co…...

初识微信小程序

新建小程序 创建一个新的微信小程序项目&#xff1a; 打开微信开发者工具&#xff0c;点击“新建项目”。 在弹出的窗口中&#xff0c;填写小程序的 AppID、项目名称和项目目录等信息。 点击“确定”按钮&#xff0c;等待微信开发者工具自动下载并安装所需的依赖库和框架。 …...

我们该如何入门编程呢

提醒&#xff1a;以下内容仅做参考&#xff0c;可自行发散。在发布作品前&#xff0c;请把不需要的内容删掉。 随着信息技术的快速发展&#xff0c;编程已经成为一个越来越重要的技能。那么&#xff0c;我们该如何入门编程呢&#xff1f;选择编程语言&#xff1a;选择一种编程…...

App 软件开发《判断6》试卷及答案

App 软件开发《判断6》试卷及答案 文章目录 App 软件开发《判断6》试卷及答案判断题&#xff08;对的打“√”&#xff0c;错的打“”&#xff1b;共0分&#xff09;1&#xff0e;”ionic resources --icon"命令用于生成适应不同分辨率的App图标所应用的图片。(✔)2&#…...

MVC工作原理

MVC工作原理 有视图的情况 1.客户端&#xff08;浏览器&#xff09;发起请求&#xff0c;DispatcherServlet拦截请求。 2.DispatcherServlet根据请求信息调用HandlerMapping。HandlerMapping根据uri去匹配查询能处理的Handler&#xff08;也就是我们所说的Controller&#x…...

使用 Redis 统计网站 UV 的方法

使用 Redis 统计网站 UV 的方法(概率算法) 文章目录 前言思路HyperLogLog 使用 Redis 命令操作使用 Java 代码操作 HyperLogLog 实现原理及特点使用 Java 实现 HyperLogLog小结 前言 网站 UV 就是指网站的独立用户访问量Unique Visitor&#xff0c;即相同用户的多次访问需要…...

黑客工具软件大全

黑客工具软件大全100套 给大家准备了全套网络安全梓料&#xff0c;有web安全&#xff0c;还有渗透测试等等内容&#xff0c;还包含电子书、面试题、pdf文档、视频以及相关的网络安全笔记 &#x1f447;&#x1f447;&#x1f447; 《黑客&网络安全入门&进阶学习包》 &a…...

uniapp主题切换功能的第二种实现方式(scss变量+require)

在上一篇 “uniapp主题切换功能的第一种实现方式&#xff08;scss变量vuex&#xff09;” 中介绍了第一种如何切换主题&#xff0c;但我们总结出一些不好的地方&#xff0c;例如扩展性不强&#xff0c;维护起来也困难等等&#xff0c;那么接下我再给大家介绍另外一种切换主题的…...

# 蓝牙音频相关知识

蓝牙音频相关知识 文章目录 蓝牙音频相关知识1 音频源2 蓝牙音频编解码器3 一些标准4 蓝牙音频其他相关知识4.1 蓝牙版本4.2 ANC&#xff08;主动降噪&#xff09;4.3 音响相关参数4.4 音质评价4.5 HI-Fi声音特点4.6 耳机线材4.7 耳机分类4.8 IP防尘防水等级4.9 噪音与量化噪音…...

【AI作画】使用DiffusionBee with stable-diffusion在mac M1平台玩AI作画

DiffusionBee是一个完全免费、离线的工具。它简洁易用&#xff0c;你只需输入一些标签或文本描述&#xff0c;它就能生成艺术图像。 DiffusionBee下载地址 运行DiffusionBee的硬性要求&#xff1a;MacOS系统版本必须在12.3及以上 DBe安装完成后&#xff0c;去C站挑选自己喜欢…...

2 STM32库函数 之 通用同步异步收发器(USART、串口)所有函数的介绍及使用

2 STM32库函数 之 通用同步异步收发器&#xff08;USART、串口&#xff09;所有函数的介绍及使用 前言一、USART固件库函数预览二、USART固件库函数具体介绍2.1 库函数 USART_DeInit2.2 库函数 USART_Init2.2.1 USART_InitTypeDef structure2.2.2 USART_InitTypeDef 成员 USART…...

SpringCloudAlibaba整合Sentinel实现流量控制熔断降级

目录 一、概念 二、整合Sentinel控制台 三、Sentinel规则配置 四、@SentinelResource资源保护注解...

CentOS 7安装 Postgre

零、前置条件 系统CentOS 7&#xff0c;并已联网&#xff0c;已安装gcc或者g编译器&#xff0c;GNU make版本3.80或以上&#xff0c;系统有至少一个除root之外的普通用户user gcc安装-参考链接查看make命令的版本——make --version更新make版本-参考链接postgresql的使用一般…...

rpc 异步非阻塞 io 配置 线程池和队列

相关 雪崩 - 如何重试 - sla和重试风暴的双保证_个人渣记录仅为自己搜索用的博客-CSDN博客 接口耗时公式 耗时 cpu时间 io时间 线程池数量 最佳数目 1s / 平均cpu时间 * 内核数. 最大平均cpu时间 接口耗时- all外部io时间. 结合gc , linux本身其他线程, 只会还少点. …...

【Turfjs的java版本JTS】前面讲了Turfjs可以实现几何计算,空间计算的功能,如果后端要做这项功能也有类似的类库,JTS

JTS Java Topology Suite 几何计算&#xff1a; 1. 前端js就用这个 Turfjs的类库。参考网站&#xff1a; 计算两线段相交点 | Turf.js中文网 2. 后端java语言就可以用 JTS这个类库&#xff0c;参考网站&#xff1a; JTS参考网站&#xff1a; 1. https://github.com/locatio…...

从Window中先多瞥几眼

JavaFx17官方文档中有如下的描述: Window类是一个顶层窗口类,在其中可以承载场景,并与用户交互。窗口可以是Stage、PopupWindow或其他类似的顶层窗口。 JavaFX Stage类是顶级的JavaFX容器。初级阶段由平台搭建。其他Stage对象可以由应用程序构造。 许多Stage属性是只读的…...

【STM32训练—WiFi模块】第二篇、STM32驱动ESP8266WiFi模块获取天气

目录 第一部分、前言 1、获取心知天气API接口 2、硬件准备 第二部分、电脑串口助手调试WIFI模块获取天气 1、ESP8266获取天气的流程 2、具体步骤 第三部分、STM32驱动ESP8266模块获取天气数据 1、天气数据的解析 1.1、什么函数来解析天气数据&#xff1f; 2.1、解析后…...

Maven私服

Maven 私服是一种特殊的远程仓库&#xff0c;它是架设在局域网内的仓库服务&#xff0c;用来代理位于外部的远程仓库&#xff08;中央仓库、其他远程公共仓库&#xff09;。 建立了 Maven 私服后&#xff0c;当局域网内的用户需要某个构件时&#xff0c;会按照如下顺序进行请求…...

手写RPC总结篇

协议制定&#xff1a;client到server做交互的通信协议&#xff0c;比如request response 网络端点peer 难点1 : Jetty嵌入 ◆jetty Server ◆ServletContextHandler ◆ServletHolder jetty server 起到网络监听的作用ServletContextHandler注册到jetty server中ServletHolde…...

c++11 标准模板(STL)(std::ios_base)成员类型与常量

流打开模式类型 std::ios_base::openmode typedef /*implementation defined*/ openmode; static constexpr openmode app /*implementation defined*/ static constexpr openmode binary /*implementation defined*/ static constexpr openmode in /*implementation defi…...

我用 ChatGPT 写 2023 高考语文作文:全国卷(一)

【2023】新高考|卷 “好的故事&#xff0c;可以帮我们更好地表达和沟通&#xff0c;可以触动心灵、启迪智慧&#xff1a;好的故事以改变一个人的命运&#xff0c;可以展现一个民族的形象故事是有力量的。” 以上材料引发了你怎样的联想和思考&#xff1f;请写一篇文章 要求&…...

4.java转义符,javadoc 标签

java常用转义字符 在控制台&#xff0c;输入tab键&#xff0c;可以实现命令补全 (如何解决cmd中Tab键不能自动补充的问题&#xff1f;百度一下) \t : 一个制表符&#xff0c;实现对齐功能\n : 换行符\ \ : 一个\\ " &#xff1a;一个"\ ’ : 一个’\r : 一个回车 …...

PinYin4j库的使用

一、PinYin4j库简介 1、PinYin4j简介 Pinyin4j 是一个流行的 Java 库&#xff0c;支持汉字和大多数流行的拼音系统之间的转换&#xff08;汉语拼音&#xff0c;罗马拼音等&#xff09;。可自定义拼音输出格式&#xff0c;功能强大。 官网地址&#xff1a;http://pinyin4j.sou…...

做网站卖装备/网页设计页面

有需求请评论或私信 可远程调试 基于PHP的毕设双选管理系统一 介绍 此毕设双选管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为学生&#xff0c;教师&#xff0c;审核员和管理员。系统核心流程为&#xff1a;学生提交选题申请后由教师…...

三九集团如何进行网站建设/群推广

理论&#xff1a; 下面的CmdObj.是定义的SqlCommand对象 1、获得存储过程中return语句返回的整个存储过程函数的返回值: //获得存储过程return的值,定义一个参数,指明其作用是接受return的值 CmdObj.Parameters.Add("RETURN_VALUE", SqlDbType.Int).Direction Par…...

大连市公众平台网站/网站注册搜索引擎的目的是

文章目录1.如何设置工程(指定Project)的SDK?2.IDEA中各种Setting的区别3.IDEA 配置全局的Maven设置4.设置编译的版本1.如何设置工程(指定Project)的SDK? 原项目的相关信息如下 接下来我修改它的项目名称为project-modify,指定该项目使用JDK1.7,并且设置该项目生成Class文件…...

wordpress+在线播放/疫情最新资讯

点击上方蓝色字体&#xff0c;选择“设为星标”回复”资源“获取更多资源大数据技术与架构点击右侧关注&#xff0c;大数据开发领域最强公众号&#xff01;大数据真好玩点击右侧关注&#xff0c;大数据真好玩&#xff01;1. JVM crash了下面是一份crash report, 下面是截取了cr…...

政府网站建设管理办法/上海网络推广

设计师同学们&#xff0c;我想大家都会在被指点江山之后&#xff0c;产生这样一个疑问&#xff1a;该如何让你的非设计师同事更好的了解设计&#xff0c;从而避免因彼此的主观而导致的理解鸿沟呢&#xff1f; 想必下面这篇文章&#xff0c;你真该要推荐他们读一下了。&#xf…...

wordpress 客户端使用/百度ai营销中国行

38-博客网站数据库-博文分类信息数据操作(二) 项目描述 当今网上微博、博客发布信息已经成为主要的信息发布、传播的系统&#xff0c;如何对这些数据进行管理&#xff0c;本项目主要是对博客网站中的博文分类信息表、博文信息表进行操作。 博客网站的数据库操作要求如下&…...