Kubernetes service account custom token - kubernetes

I am trying to create a service account with a known, fixed token used by Jenkins to deploy stuff into kubernetes. I manage to create the token all right with the following yaml:
apiVersion: v1
kind: Secret
metadata:
name: integration-secret
annotations:
kubernetes.io/service-account.name: integration
type: kubernetes.io/service-account-token
data:
token: YXNkCg== # yes this base64
Then I've attached the secret to 'integration' user and it's visible:
-> kubectl describe sa integration
Name: integration
Namespace: default
Labels: <none>
Annotations: <none>
Mountable secrets: integration-secret
integration-token-283k9
Tokens: integration-secret
integration-token-283k9
Image pull secrets: <none>
But the login fails. If i remove the data and data.token, the token get auto-created and login works. Is there something I'm missing? My goal is to have fixed token for CI so that I won't have to update it everywhere when creating a project (don't worry this is just dev environments). Is it possible for example to define username/password for service accounts for API access?

Is it possible for example to define username/password for service accounts for API access?
No, the tokens must be valid JWTs, signed by the service account token signing key.

Related

Integrating SSO for Argo Workflows using Keycloak

I have a requirement to integrate SSO for Argo-workflow and for these we have made necessary changes in quick-start-postgres.yaml.
Here is the yaml file we are using to start argo locally.
https://raw.githubusercontent.com/argoproj/argo-workflows/master/manifests/quick-start-postgres.yaml
And below are the sections we are modifying to support for SSO integration
Deployment section:
apiVersion: apps/v1
kind: Deployment
metadata:
name: argo-server
spec:
selector:
matchLabels:
app: argo-server
template:
metadata:
labels:
app: argo-server
spec:
containers:
- args:
- server
- --namespaced
- --auth-mode=sso
workflow-controller-configmap section :
apiVersion: v1
data:
sso: |
# This is the root URL of the OIDC provider (required).
issuer: http://localhost:8080/auth/realms/master
# This is name of the secret and the key in it that contain OIDC client
# ID issued to the application by the provider (required).
clientId:
name: dummyClient
key: client-id
# This is name of the secret and the key in it that contain OIDC client
# secret issued to the application by the provider (required).
clientSecret:
name: jdgcFxs26SdxdpH9Z5L33QCFAmGYTzQB
key: client-secret
# This is the redirect URL supplied to the provider (required). It must
# be in the form <argo-server-root-url>/oauth2/callback. It must be
# browser-accessible.
redirectUrl: http://localhost:2746/oauth2/callback
artifactRepository: |
s3:
bucket: my-bucket
We are starting the argo by issuing below 2 commands
kubectl apply -n argo -f modified-file/quick-start-postgres.yaml
kubectl -n argo port-forward svc/argo-server 2746:2746
After executing above commands and trying to login as Single-sign on , it is not getting redirected to provide login option for keycloak user. Instead it us redirected to https://localhost:2746/oauth2/redirect?redirect=https://localhost:2746/workflows
This page isn’t working localhost is currently unable to handle this request.
HTTP ERROR 501
What could be the issue here ? are we missing anything here ??
Is there arguments needed to pass while starting the Argo?
Can someone please suggest something on this.
Try adding --auth-mode=client to your argo-server container args

Kubernetes Security: How to check the token of service account?

First, I have created a service account jenkins
> kubectl create serviceaccount jenkins
serviceaccount/jenkins created
Second, create a token for this service account.
> kubectl create token jenkins
eyJhbGc****************iQS-AVXfIzA
Then, I run kubectl describe serviceaccount jenkins command to check the tokens of newly created service account.
But the output shows None tokens.
> kubectl describe serviceaccount jenkins
Name: jenkins
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: <none> <===== look at this!
Events: <none>
Questions
The output shows "None" tokens, how do I know there is a token associated with this service account?
If I run kubectl create token jenkins command multiple times, will kubernetes create multiple tokens for this account? or the latest one will overwrite the previous one?
# first time
kubectl create token jenkins
# second time
kubectl create token jenkins
# third time
kubectl create token jenkins
`
What's the mapping relation between the service account and the token? is it 1:n ?
The mechanism of service accounts and tokens has been changed (Moved to stable in v1.22).
In the past, you have created a service account. Then in the first time you ran a pod with that service account, Kubernetes created a long-lived, never expired, token that resided in secret of type kubernetes.io/service-account-token. Kubernetes attached this token to the pod via volume mount.
Due to the unsecured nature of long-lived tokens this has been changed to something called Bound Service Account Token Volumes.
In short, Kubernetes no more creates a secret with a token for the service account but instead Kubelet injects a short-lived token with a default timespan of 1 hour to the pod and refresh it when it's expired.
When you ran kubectl describe serviceaccount jenkins you saw <none> in the section of the Tokens because it represents the 'old fashioned' static tokens that as mentioned are not created by default anymore.
You can manually create such a static token with
> cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: jenkins
annotations:
kubernetes.io/service-account.name: jenkins
EOF
and then when you run describe again and you will the new token
> kubectl describe serviceaccount jenkins
Name: jenkins
Namespace: jenkins-demo
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: jenkins
Events: <none>
You can create multiple tokens with different names and you will see all of them in the describe output.
BUT This is a bad practice to create these static tokens because they never expired. You should use short-lived token that you can create with the command you mentioned kubectl create token jenkins
You can control the duration with --duration <seconds>s and create a token with an expiration of up to 48h. The default is 1h.
The creation of new token doesn't overwrite the previous one. These tokens are JWTs - meaning they are signed and distributed, and are not kept on the server. If you want to see the content of a token you can paste the output
of kubectl create token jenkins in jwt.io.
Same as with the static token. You can run
kubectl get secret jenkins --output=jsonpath='{.data.token}' | base64 -d
and paste the output in jwt.io. You can notice this token doesn't have an expiration date.
Reference:
https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#manually-create-an-api-token-for-a-serviceaccount
https://github.com/kubernetes/enhancements/tree/master/keps/sig-auth/1205-bound-service-account-tokens
https://github.com/kubernetes/enhancements/issues/542

Service account secret is not listed. How to fix it?

I have used kubectl create serviceaccount sa1 to create service account. Then I used kubectl get serviceaccount sa1 -oyaml command to get service account info. But it returns as below.
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2022-05-16T08:03:50Z"
name: sa1
namespace: default
resourceVersion: "19651"
uid: fdddacba-be9d-4e77-a849-95ca243781cc
I need to get,
secrets:
- name: <secret>
part. but it doesn't return secrets. How to fix it?
In Kubernetes 1.24, ServiceAccount token secrets are no longer automatically generated. See "Urgent Upgrade Notes" in the 1.24 changelog file:
The LegacyServiceAccountTokenNoAutoGeneration feature gate is beta, and enabled by default. When enabled, Secret API objects containing service account tokens are no longer auto-generated for every ServiceAccount. Use the TokenRequest API to acquire service account tokens, or if a non-expiring token is required, create a Secret API object for the token controller to populate with a service account token by following this guide. (#108309, #zshihang)
This means, in Kubernetes 1.24, you need to manually create the Secret; the token key in the data field will be automatically set for you.
apiVersion: v1
kind: Secret
metadata:
name: sa1-token
annotations:
kubernetes.io/service-account.name: sa1
type: kubernetes.io/service-account-token
Since you're manually creating the Secret, you know its name: and don't need to look it up in the ServiceAccount object.
This approach should work fine in earlier versions of Kubernetes too.

Does RBAC rules apply to pods?

I have the following pod definition, (notice the explicitly set service account and secret):
apiVersion: v1
kind: Pod
metadata:
name: pod-service-account-example
labels:
name: pod-service-account-example
spec:
serviceAccountName: example-sa
containers:
- name: busybox
image: busybox:latest
command: ["sleep", "10000000"]
env:
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: example-secret
key: secret-key-123
It successfully runs. However if I use the the same service account example-sa, and try to retrieve the example-secret it fails:
kubectl get secret example-secret
Error from server (Forbidden): secrets "example-secret" is forbidden: User "system:serviceaccount:default:example-sa" cannot get resource "secrets" in API group "" in the namespace "default"
Does RBAC not apply for pods? Why is the pod able to retrieve the secret if not?
RBAC applies to service accounts, groups, users and not to pods.When you refer a secret in the env of a pod , service account is not being used to get the secret.Kubelet is getting the secret by using its own kubernetes client credential. Since kubelet is using its own credential to get the secret it does not matter whether the service account has RBAC to get secret or not because its not used.
Service account is used when you want to invoke Kubernetes API from a pod using kubernetes standard client library or Kubectl.
Code snippet of Kubelet for reference.

AWS EKS enable basic auth

Is it possible to enable k8s basic auth in AWS EKS?
I need it to make Jenkins Kubernetes plugin work when Jenkins is deployed outside k8s.
You can use service account tokens.
Read more about it here: https://kubernetes.io/docs/reference/access-authn-authz/authentication/#service-account-tokens
You can use service account tokens (as Bearer Tokens).
Service account bearer tokens are perfectly valid to use outside the cluster and can be used to create identities for long standing jobs that wish to talk to the Kubernetes API. To manually create a service account, simply use the kubectl create serviceaccount (NAME) command. This creates a service account in the current namespace and an associated secret.
kubectl create serviceaccount jenkins
serviceaccount "jenkins" created
Check an associated secret:
kubectl get serviceaccounts jenkins -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
# ...
secrets:
- name: jenkins-token-1yvwg
The created secret holds the public CA of the API server and a signed JSON Web Token (JWT).
kubectl get secret jenkins-token-1yvwg -o yaml
apiVersion: v1
data:
ca.crt: (APISERVER'S CA BASE64 ENCODED)
namespace: ZGVmYXVsdA==
token: (BEARER TOKEN BASE64 ENCODED)
kind: Secret
metadata:
# ...
type: kubernetes.io/service-account-token
The signed JWT can be used as a bearer token to authenticate as the given service account.
If you need more control, install nginx-ingress and then tell it to enforce HTTP Basic authentication.
https://kubernetes.github.io/ingress-nginx/examples/auth/basic/
https://aws.amazon.com/blogs/opensource/network-load-balancer-nginx-ingress-controller-eks/
https://www.rfc-editor.org/rfc/rfc7617