Service Accounts
Faça uma revisão em cka service accounts.
O que precisamos incluir.
Não é possível criar um pod com um service account que não existe.
É boa prática que cada aplicação crie um service account mesmo que não faça um binding com nenhuma role ou cluster role. Esta SA pode ser usada em aplicações que não precisem de acesso ao cluster.
Se não definimos o serviceAccountName no pod o SA default será usado. Imagine que todos os pods do mesmo namespace estejam usado a service account default, se um deles precisar de alguma permissão maior nesta service account todos os outros pods que terão a mesma permissão sem necessidade.
Um outro detalhe que devemos nos atentar é que a maioria das aplicações não precisam de acesso à API do Kubernetes sendo que a SA é exatamente para isso. Nesse caso podemos evitar que o token seja montado cortando totalmente o acesso.
kubectl run nginx --image=nginx -o yaml --dry-run=client
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: nginx
name: nginx
spec:
containers:
- image: nginx
name: nginx
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
kubectl run nginx --image=nginx -o yaml --dry-run=client > pod-nginx.yaml
k apply -f pod-nginx.yaml
# Vamos para dentro do pod conferir uns detalhes
k exec -it nginx -- bash
root@nginx:/# cd /run/secrets/kubernetes.io/serviceaccount/
root@nginx:/run/secrets/kubernetes.io/serviceaccount# ls
ca.crt namespace token
root@nginx:/run/secrets/kubernetes.io/serviceaccount# cat namespace
default
root@nginx:/run/secrets/kubernetes.io/serviceaccount# cat token
eyJhbGciOiJSUzI1NiIsImtpZCI6InNOUENuTnQxUVVoYjBrb0NTWXJMdE14ZW4xSzd1VHYtVGpwYWNRV1JYcncifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzU1ODA4NDA0LCJpYXQiOjE3MjQyNzI0MDQsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiZjI3NzUzM2EtYWRhNi00M2EzLWI2YWUtYjY5YTk1MTJjYWU0Iiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwibm9kZSI6eyJuYW1lIjoicGVyc29uYWwtY2x1c3Rlci13b3JrZXIzIiwidWlkIjoiYWIwOWU2YzAtMDg5NC00ZjkwLWJlMGQtYzIzYTc5NzA5N2FkIn0sInBvZCI6eyJuYW1lIjoibmdpbngiLCJ1aWQiOiI2Njk2Y2IzMy01YzlmLTQzYmUtYjRhYS1kYjAxZmIwOTg2YjUifSwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlZmF1bHQiLCJ1aWQiOiJhYjAyODA5ZS0yNDAxLTQ2ZmYtYTNjNi0wMzc4OTdkMGQxZmUifSwid2FybmFmdGVyIjoxNzI0Mjc2MDExfSwibmJmIjoxNzI0MjcyNDA0LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpkZWZhdWx0In0.WgmNnF2dblSDjnlbH9j0MuzRu4yX1XKj4Q3wTlkQi-r482HNT-vsyHmmtJwy_6XLEFgMeNe0NSizhrRpgluYPdERwQcyaX8Y_GX0GIM0eGaiGm0qHS31oK115Ch_7SaGHPRdNv-cNQutQz1R-8ptTXEnxRNK2a8furX-mWPBXMdQkTrgObOBWnmP-O0lsiCBqCFDQmw6qXTIUby-7ipg3M82xBp8JP_ml-nOpFI5cMoq2SKcaryOk2t8mWT1KdsrROmtuQrEqcK_eBD6KY2Sm84VrB_XWHdUJ3jikn5utpIkiqzWjFntHoos5asVxNwvH-R_Y2_xKqGzxYsCU9b1pg
root@nginx:/run/secrets/kubernetes.io/serviceaccount# env | grep KUBE
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PORT=443
# Vamos tentar chegar na api, mas temos um problema, estamos nos autenticando como system:anonymous.
root@nginx:/run/secrets/kubernetes.io/serviceaccount# curl https://$KUBERNETES_SERVICE_HOST -k
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
"reason": "Forbidden",
"details": {},
"code": 403
}
# Vamos passar o token. Esse token sendo service account default vamos nos autenticar como system:serviceaccount:default:default
root@nginx:/run/secrets/kubernetes.io/serviceaccount# curl https://$KUBERNETES_SERVICE_HOST -k -H "Authorization: Bearer $(cat token)"
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "forbidden: User \"system:serviceaccount:default:default\" cannot get path \"/\"",
"reason": "Forbidden",
"details": {},
"code": 403
}
root@nginx:/run/secrets/kubernetes.io/serviceaccount# curl https://$KUBERNETES_SERVICE_HOST/version -k -H "Authorization: Bearer $(cat token)"
{
"major": "1",
"minor": "30",
"gitVersion": "v1.30.0",
"gitCommit": "7c48c2bd72b9bf5c44d21d7338cc7bea77d0ad2a",
"gitTreeState": "clean",
"buildDate": "2024-05-13T22:00:36Z",
"goVersion": "go1.22.2",
"compiler": "gc",
"platform": "linux/amd64"
}
exit
# E só para mostrar que os volumes foram montados
❯ k get pod nginx -o yaml
apiVersion: v1
kind: Pod
metadata:
...
namespace: default
resourceVersion: "11254882"
uid: 08243b7c-1208-49a7-affc-58348a481cb6
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: nginx
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount #<<<<
name: kube-api-access-mmcdn
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
nodeName: personal-cluster-worker3
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
# Aqui temos os os volumes com os arquivos
volumes:
- name: kube-api-access-mmcdn
projected:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token #<<<<
- configMap:
items:
- key: ca.crt
path: ca.crt #<<<<
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace #<<<<
Geralmente um pod não precisa acessar a API a menos que seja parte de um operator que irá trabalhar com recursos do cluster.
Agora vamos criar o mesmo pod com service account específico e retirar o automount do token. Edit o arquivo pod-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx
name: nginx
spec:
# Definimos a service account e desativamos o automount
serviceAccountName: acessor # um service account que já existe no namespace
automountServiceAccountToken: false
containers:
- image: nginx
name: nginx
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
❯ k replace -f pod-nginx.yaml --force
pod "nginx" deleted
pod/nginx replaced
# Não montou nem a pasta secrets
k exec -it nginx -- bash
root@nginx:/# ls /run/
lock/ nginx.pid
exit
# E podemos conferir que não montou nem um volume
❯ k get pod nginx -o yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2024-08-21T20:55:24Z"
labels:
run: nginx
name: nginx
namespace: default
resourceVersion: "11253497"
uid: 362c77fb-e4dc-4195-9287-0fa3fcabf4d7
spec:
automountServiceAccountToken: false
containers:
- image: nginx
imagePullPolicy: Always
name: nginx
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
enableServiceLinks: true
nodeName: personal-cluster-worker3
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: acessor # Service account usada
serviceAccountName: acessor
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2024-08-21T20:55:26Z"
status: "True"
type: PodReadyToStartContainers
- lastProbeTime: null
lastTransitionTime: "2024-08-21T20:55:24Z"
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: "2024-08-21T20:55:26Z"
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: "2024-08-21T20:55:26Z"
status: "True"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: "2024-08-21T20:55:24Z"
status: "True"
type: PodScheduled
containerStatuses:
- containerID: containerd://747371ca8c09824d1689d89cee6c494431eb6bf6cbaa68bfb11daae12b8c8c70
image: docker.io/library/nginx:latest
imageID: docker.io/library/nginx@sha256:447a8665cc1dab95b1ca778e162215839ccbb9189104c79d7ec3a81e14577add
lastState: {}
name: nginx
ready: true
restartCount: 0
started: true
state:
running:
startedAt: "2024-08-21T20:55:25Z"
hostIP: 172.18.0.4
hostIPs:
- ip: 172.18.0.4
phase: Running
podIP: 10.32.0.11
podIPs:
- ip: 10.32.0.11
qosClass: BestEffort
startTime: "2024-08-21T20:55:24Z"