ServiceAccount 无法删除部署或服务,但能够创建它
ServiceAccount unable to delete a deployment or service, but is able to create it
Kubernetes v1.20.0,在 Ubuntu 20.04.1,docker 19.3.11
使用以下配置,我可以使用此服务帐户的令牌在命名空间“实时”中创建部署,但我无法使用相同的令牌删除部署。
正在尝试找到正确的角色以绑定到我的编程 ServiceAccount 用户,但我无法获得用于部署删除的正确角色映射。我试过使用和不使用斜杠、资源名称中的星号以及复数形式的资源。
这是我从 API 得到的错误:
warnings.warn(
Exception (403)
Reason: Forbidden
HTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'X-Content-Type-Options': 'nosniff', 'X-Kubernetes-Pf-Flowschema-Uid': 'xxxx-bf2f-43b3-af5d-3ce15b086080', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'xxxx-0d42-4b08-820e-396249f74107', 'Date': 'Mon, 28 Dec 2020 13:33:00 GMT', 'Content-Length': '408'})
HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"deployments.apps \"live-stream-deploy-testing123\" is forbidden: User \"system:serviceaccount:live:live-serviceaccount\" cannot delete resource \"deployments\" in API group \"apps\" in the namespace \"live\"","reason":"Forbidden","details":{"name":"live-stream-deploy-testing123","group":"apps","kind":"deployments"},"code":403}
这是我要删除的部署:
$ kubectl -n live get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
live-stream-deploy-testing123 1/1 1 1 76m
这是我目前的角色定义(我已经尝试在资源名称中使用星号,这对创建无效,后来进行了多次迭代:):
$ kubectl -n live describe role
Name: live-serviceaccount-role
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
deployment/ [] [] [get watch create list delete]
deployment [] [] [get watch create list delete]
deployments/ [] [] [get watch create list delete]
deployments [] [] [get watch create list delete]
service/ [] [] [get watch create list delete]
service [] [] [get watch create list delete]
services/ [] [] [get watch create list delete]
services [] [] [get watch create list delete]
services [] [] [get watch create list delete]
deployment.apps/ [] [] [get watch create list delete]
deployment.apps [] [] [get watch create list delete]
deployments.apps/ [] [] [get watch create list delete]
deployments.apps [] [] [get watch create list delete]
service.apps/ [] [] [get watch create list delete]
service.apps [] [] [get watch create list delete]
services.apps/ [] [] [get watch create list delete]
services.apps [] [] [get watch create list delete]
角色绑定:
$ kubectl -n live describe rolebindings
Name: live-serviceaccount-rolebinding
Labels: <none>
Annotations: <none>
Role:
Kind: Role
Name: live-serviceaccount-role
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount live-serviceaccount live
pip 包 kubernetes==12.0.1。我没有针对以前的版本对其进行测试。
导致错误的脚本:
import kubernetes.client
from kubernetes.client.rest import ApiException
import logging
logger = logging.getLogger(__name__)
DEPLOYMENT_NAME = "live-stream-deploy-testing123"
configuration = kubernetes.client.Configuration()
configuration.api_key['authorization'] = "service account token here..."
configuration.api_key_prefix['authorization'] = 'Bearer'
configuration.verify_ssl = False
configuration.host = "https://my_k8s_API:6443"
with kubernetes.client.ApiClient(configuration) as api_client:
try:
api_instance = kubernetes.client.AppsV1Api(api_client)
api_instance.delete_namespaced_deployment(
name=DEPLOYMENT_NAME, namespace="live")
logger.info("Deployment deleted. %s" % DEPLOYMENT_NAME)
except ApiException as e:
logger.error("Exception %s\n" % e)
一些额外的“can-i”操作:
$ kubectl -n live auth can-i --as=system:serviceaccount:live:live-serviceaccount delete deploy
yes
$ kubectl auth can-i --as=system:serviceaccount:live:live-serviceaccount --list -n live
Resources Non-Resource URLs Resource Names Verbs
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
deployment/ [] [] [get watch create list delete]
deployment [] [] [get watch create list delete]
deployments/ [] [] [get watch create list delete]
deployments [] [] [get watch create list delete]
service/ [] [] [get watch create list delete]
service [] [] [get watch create list delete]
services/ [] [] [get watch create list delete]
services [] [] [get watch create list delete]
deployment.apps/ [] [] [get watch create list delete]
deployment.apps [] [] [get watch create list delete]
deployments.apps/ [] [] [get watch create list delete]
deployments.apps [] [] [get watch create list delete]
service.apps/ [] [] [get watch create list delete]
service.apps [] [] [get watch create list delete]
services.apps/ [] [] [get watch create list delete]
services.apps [] [] [get watch create list delete]
[/.well-known/openid-configuration] [] [get]
[/api/*] [] [get]
[/api] [] [get]
[/apis/*] [] [get]
[/apis] [] [get]
[/healthz] [] [get]
[/healthz] [] [get]
[/livez] [] [get]
[/livez] [] [get]
[/openapi/*] [] [get]
[/openapi] [] [get]
[/openid/v1/jwks] [] [get]
[/readyz] [] [get]
[/readyz] [] [get]
[/version/] [] [get]
[/version/] [] [get]
[/version] [] [get]
[/version] [] [get]
这是生成上述输出的 YAML。它们都在 live 命名空间中。请原谅角色上的混乱,但我一直在尝试迭代以找到解决方案:
$ cat role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: live-serviceaccount-role
namespace: live
rules:
- apiGroups: ["","apps"]
resources: ["services", "services/", "deployment", "deployment/", "service", "service/", "deployments", "deployments/"]
resourceNames: [""]
verbs: ["get", "watch", "create", "list", "delete"]
- apiGroups: [""]
resources: ["services"]
resourceNames: [""]
verbs: ["get", "watch", "create", "list", "delete"]
$ cat serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: live-serviceaccount
namespace: live
$ cat rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: live-serviceaccount-rolebinding
namespace: live
subjects:
- kind: ServiceAccount
name: live-serviceaccount # "name" is case sensitive
namespace: live
roleRef:
kind: Role #this must be Role or ClusterRole
name: live-serviceaccount-role # this must match the name of the Role or ClusterRole you wish to bind to
apiGroup: "rbac.authorization.k8s.io"
以下是成功启动实时命名空间中部署的脚本示例:
import kubernetes.client
from kubernetes import client
import logging
logger = logging.getLogger(__name__)
DEPLOYMENT_NAME = "live-stream-deploy-testing123"
POD_APP_LABEL = "lab"
configuration = kubernetes.client.Configuration()
# Configure API key authorization: BearerToken
configuration.api_key['authorization'] = "service account token here..."
# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed
configuration.api_key_prefix['authorization'] = 'Bearer'
configuration.verify_ssl = False
# Defining host is optional and default to http://localhost
configuration.host = "https://<myk8sapi>:6443"
# Enter a context with an instance of the API kubernetes.client
#with kubernetes.client.ApiClient(configuration) as api_client:
with kubernetes.client.ApiClient(configuration) as api_client:
api_instance = kubernetes.client.AppsV1Api(api_client)
def create_deployment_object():
# Configureate Pod template container
container = kubernetes.client.V1Container(
name="lab-container",
# redacted for privacy
image="nginx:latest",
termination_message_path="/var/log/messages",
image_pull_policy="IfNotPresent",
resources=client.V1ResourceRequirements(
requests={"memory": "5Gi"},
limits={"memory": "16Gi"}
),
volume_mounts=[
client.V1VolumeMount(mount_path="/etc/nginx/nginx.conf.template", name="nginxconftemplate", sub_path="nginx.conf")
]
)
volume1 = client.V1Volume(
name="nginxconftemplate",
config_map=client.V1ConfigMapVolumeSource(
name="live-nginx-conf",
default_mode=0o0777
)
)
# Create and configurate a spec section
template = client.V1PodTemplateSpec(
metadata=client.V1ObjectMeta(labels={"app": POD_APP_LABEL}),
spec=client.V1PodSpec(containers=[container],
volumes=[volume1],
node_selector={"backend": "yes"},
)
)
# Create the specification of deployment
spec = client.V1DeploymentSpec(
replicas=1,
template=template,
selector={'matchLabels': {'app': POD_APP_LABEL}})
# Instantiate the deployment object
deployment = client.V1Deployment(
api_version="apps/v1",
kind="Deployment",
metadata=client.V1ObjectMeta(name=DEPLOYMENT_NAME),
spec=spec)
return deployment
def create_deployment(api_instance, deployment):
# Create deployement
api_response = api_instance.create_namespaced_deployment(
body=deployment,
namespace="live")
logger.info("Deployment created. status='%s'" % str(api_response.status))
deployment = create_deployment_object()
create_deployment(api_instance, deployment)
以下是适合我的正确角色定义:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: live-serviceaccount-role
namespace: live
rules:
- apiGroups: ["","apps"] # "" indicates the core API group
resources: ["deployments"]
verbs: ["create", "delete"]
产生这个 can-i 输出:
$ kubectl auth can-i --as=system:serviceaccount:live:live-serviceaccount --list -n live
Resources Non-Resource URLs Resource Names Verbs
deployments [] [] [create delete]
deployments.apps [] [] [create delete]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
[/api/*] [] [get]
[/api] [] [get]
[/apis/*] [] [get]
[/apis] [] [get]
[/healthz] [] [get]
[/healthz] [] [get]
[/livez] [] [get]
[/livez] [] [get]
[/openapi/*] [] [get]
[/openapi] [] [get]
[/readyz] [] [get]
[/readyz] [] [get]
[/version/] [] [get]
[/version/] [] [get]
[/version] [] [get]
[/version] [] [get]
虽然您的回答涵盖了解决方案,但并未解释为什么您提供的新角色集与之前的角色相比运行成功。
can-i
命令在这种情况下有点误导。结果实际上是正确的,因为使用此角色您只能删除 chosen/mentioned 资源。由于您使用 resourceNames
和一个空列表 [""]
,您的角色不允许删除任何内容。
为了简单地测试这个,我将确切的部署名称放在 resourceNames
:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: live-serviceaccount-role
namespace: live
rules:
- apiGroups: ["","apps"]
resources: ["services", "services/", "deployment", "deployment/", "service", "service/", "deployments", "deployments/"]
resourceNames: ["live-stream-deploy-testing123"]
verbs: ["get", "watch", "create", "list", "delete"]
完成后,我启动了您的代码,部署已成功删除。
所以总结一下你应该用资源名称填充 resourceNames
或完全省略它。
Kubernetes v1.20.0,在 Ubuntu 20.04.1,docker 19.3.11
使用以下配置,我可以使用此服务帐户的令牌在命名空间“实时”中创建部署,但我无法使用相同的令牌删除部署。
正在尝试找到正确的角色以绑定到我的编程 ServiceAccount 用户,但我无法获得用于部署删除的正确角色映射。我试过使用和不使用斜杠、资源名称中的星号以及复数形式的资源。
这是我从 API 得到的错误:
warnings.warn(
Exception (403)
Reason: Forbidden
HTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'X-Content-Type-Options': 'nosniff', 'X-Kubernetes-Pf-Flowschema-Uid': 'xxxx-bf2f-43b3-af5d-3ce15b086080', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'xxxx-0d42-4b08-820e-396249f74107', 'Date': 'Mon, 28 Dec 2020 13:33:00 GMT', 'Content-Length': '408'})
HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"deployments.apps \"live-stream-deploy-testing123\" is forbidden: User \"system:serviceaccount:live:live-serviceaccount\" cannot delete resource \"deployments\" in API group \"apps\" in the namespace \"live\"","reason":"Forbidden","details":{"name":"live-stream-deploy-testing123","group":"apps","kind":"deployments"},"code":403}
这是我要删除的部署:
$ kubectl -n live get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
live-stream-deploy-testing123 1/1 1 1 76m
这是我目前的角色定义(我已经尝试在资源名称中使用星号,这对创建无效,后来进行了多次迭代:):
$ kubectl -n live describe role
Name: live-serviceaccount-role
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
deployment/ [] [] [get watch create list delete]
deployment [] [] [get watch create list delete]
deployments/ [] [] [get watch create list delete]
deployments [] [] [get watch create list delete]
service/ [] [] [get watch create list delete]
service [] [] [get watch create list delete]
services/ [] [] [get watch create list delete]
services [] [] [get watch create list delete]
services [] [] [get watch create list delete]
deployment.apps/ [] [] [get watch create list delete]
deployment.apps [] [] [get watch create list delete]
deployments.apps/ [] [] [get watch create list delete]
deployments.apps [] [] [get watch create list delete]
service.apps/ [] [] [get watch create list delete]
service.apps [] [] [get watch create list delete]
services.apps/ [] [] [get watch create list delete]
services.apps [] [] [get watch create list delete]
角色绑定:
$ kubectl -n live describe rolebindings
Name: live-serviceaccount-rolebinding
Labels: <none>
Annotations: <none>
Role:
Kind: Role
Name: live-serviceaccount-role
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount live-serviceaccount live
pip 包 kubernetes==12.0.1。我没有针对以前的版本对其进行测试。 导致错误的脚本:
import kubernetes.client
from kubernetes.client.rest import ApiException
import logging
logger = logging.getLogger(__name__)
DEPLOYMENT_NAME = "live-stream-deploy-testing123"
configuration = kubernetes.client.Configuration()
configuration.api_key['authorization'] = "service account token here..."
configuration.api_key_prefix['authorization'] = 'Bearer'
configuration.verify_ssl = False
configuration.host = "https://my_k8s_API:6443"
with kubernetes.client.ApiClient(configuration) as api_client:
try:
api_instance = kubernetes.client.AppsV1Api(api_client)
api_instance.delete_namespaced_deployment(
name=DEPLOYMENT_NAME, namespace="live")
logger.info("Deployment deleted. %s" % DEPLOYMENT_NAME)
except ApiException as e:
logger.error("Exception %s\n" % e)
一些额外的“can-i”操作:
$ kubectl -n live auth can-i --as=system:serviceaccount:live:live-serviceaccount delete deploy
yes
$ kubectl auth can-i --as=system:serviceaccount:live:live-serviceaccount --list -n live
Resources Non-Resource URLs Resource Names Verbs
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
deployment/ [] [] [get watch create list delete]
deployment [] [] [get watch create list delete]
deployments/ [] [] [get watch create list delete]
deployments [] [] [get watch create list delete]
service/ [] [] [get watch create list delete]
service [] [] [get watch create list delete]
services/ [] [] [get watch create list delete]
services [] [] [get watch create list delete]
deployment.apps/ [] [] [get watch create list delete]
deployment.apps [] [] [get watch create list delete]
deployments.apps/ [] [] [get watch create list delete]
deployments.apps [] [] [get watch create list delete]
service.apps/ [] [] [get watch create list delete]
service.apps [] [] [get watch create list delete]
services.apps/ [] [] [get watch create list delete]
services.apps [] [] [get watch create list delete]
[/.well-known/openid-configuration] [] [get]
[/api/*] [] [get]
[/api] [] [get]
[/apis/*] [] [get]
[/apis] [] [get]
[/healthz] [] [get]
[/healthz] [] [get]
[/livez] [] [get]
[/livez] [] [get]
[/openapi/*] [] [get]
[/openapi] [] [get]
[/openid/v1/jwks] [] [get]
[/readyz] [] [get]
[/readyz] [] [get]
[/version/] [] [get]
[/version/] [] [get]
[/version] [] [get]
[/version] [] [get]
这是生成上述输出的 YAML。它们都在 live 命名空间中。请原谅角色上的混乱,但我一直在尝试迭代以找到解决方案:
$ cat role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: live-serviceaccount-role
namespace: live
rules:
- apiGroups: ["","apps"]
resources: ["services", "services/", "deployment", "deployment/", "service", "service/", "deployments", "deployments/"]
resourceNames: [""]
verbs: ["get", "watch", "create", "list", "delete"]
- apiGroups: [""]
resources: ["services"]
resourceNames: [""]
verbs: ["get", "watch", "create", "list", "delete"]
$ cat serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: live-serviceaccount
namespace: live
$ cat rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: live-serviceaccount-rolebinding
namespace: live
subjects:
- kind: ServiceAccount
name: live-serviceaccount # "name" is case sensitive
namespace: live
roleRef:
kind: Role #this must be Role or ClusterRole
name: live-serviceaccount-role # this must match the name of the Role or ClusterRole you wish to bind to
apiGroup: "rbac.authorization.k8s.io"
以下是成功启动实时命名空间中部署的脚本示例:
import kubernetes.client
from kubernetes import client
import logging
logger = logging.getLogger(__name__)
DEPLOYMENT_NAME = "live-stream-deploy-testing123"
POD_APP_LABEL = "lab"
configuration = kubernetes.client.Configuration()
# Configure API key authorization: BearerToken
configuration.api_key['authorization'] = "service account token here..."
# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed
configuration.api_key_prefix['authorization'] = 'Bearer'
configuration.verify_ssl = False
# Defining host is optional and default to http://localhost
configuration.host = "https://<myk8sapi>:6443"
# Enter a context with an instance of the API kubernetes.client
#with kubernetes.client.ApiClient(configuration) as api_client:
with kubernetes.client.ApiClient(configuration) as api_client:
api_instance = kubernetes.client.AppsV1Api(api_client)
def create_deployment_object():
# Configureate Pod template container
container = kubernetes.client.V1Container(
name="lab-container",
# redacted for privacy
image="nginx:latest",
termination_message_path="/var/log/messages",
image_pull_policy="IfNotPresent",
resources=client.V1ResourceRequirements(
requests={"memory": "5Gi"},
limits={"memory": "16Gi"}
),
volume_mounts=[
client.V1VolumeMount(mount_path="/etc/nginx/nginx.conf.template", name="nginxconftemplate", sub_path="nginx.conf")
]
)
volume1 = client.V1Volume(
name="nginxconftemplate",
config_map=client.V1ConfigMapVolumeSource(
name="live-nginx-conf",
default_mode=0o0777
)
)
# Create and configurate a spec section
template = client.V1PodTemplateSpec(
metadata=client.V1ObjectMeta(labels={"app": POD_APP_LABEL}),
spec=client.V1PodSpec(containers=[container],
volumes=[volume1],
node_selector={"backend": "yes"},
)
)
# Create the specification of deployment
spec = client.V1DeploymentSpec(
replicas=1,
template=template,
selector={'matchLabels': {'app': POD_APP_LABEL}})
# Instantiate the deployment object
deployment = client.V1Deployment(
api_version="apps/v1",
kind="Deployment",
metadata=client.V1ObjectMeta(name=DEPLOYMENT_NAME),
spec=spec)
return deployment
def create_deployment(api_instance, deployment):
# Create deployement
api_response = api_instance.create_namespaced_deployment(
body=deployment,
namespace="live")
logger.info("Deployment created. status='%s'" % str(api_response.status))
deployment = create_deployment_object()
create_deployment(api_instance, deployment)
以下是适合我的正确角色定义:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: live-serviceaccount-role
namespace: live
rules:
- apiGroups: ["","apps"] # "" indicates the core API group
resources: ["deployments"]
verbs: ["create", "delete"]
产生这个 can-i 输出:
$ kubectl auth can-i --as=system:serviceaccount:live:live-serviceaccount --list -n live
Resources Non-Resource URLs Resource Names Verbs
deployments [] [] [create delete]
deployments.apps [] [] [create delete]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
[/api/*] [] [get]
[/api] [] [get]
[/apis/*] [] [get]
[/apis] [] [get]
[/healthz] [] [get]
[/healthz] [] [get]
[/livez] [] [get]
[/livez] [] [get]
[/openapi/*] [] [get]
[/openapi] [] [get]
[/readyz] [] [get]
[/readyz] [] [get]
[/version/] [] [get]
[/version/] [] [get]
[/version] [] [get]
[/version] [] [get]
虽然您的回答涵盖了解决方案,但并未解释为什么您提供的新角色集与之前的角色相比运行成功。
can-i
命令在这种情况下有点误导。结果实际上是正确的,因为使用此角色您只能删除 chosen/mentioned 资源。由于您使用 resourceNames
和一个空列表 [""]
,您的角色不允许删除任何内容。
为了简单地测试这个,我将确切的部署名称放在 resourceNames
:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: live-serviceaccount-role
namespace: live
rules:
- apiGroups: ["","apps"]
resources: ["services", "services/", "deployment", "deployment/", "service", "service/", "deployments", "deployments/"]
resourceNames: ["live-stream-deploy-testing123"]
verbs: ["get", "watch", "create", "list", "delete"]
完成后,我启动了您的代码,部署已成功删除。
所以总结一下你应该用资源名称填充 resourceNames
或完全省略它。