Merge pull request #31845 from liggitt/manual-token
Stop recommending people scrape auto-generated service account tokens
This commit is contained in:
		
						commit
						9de083393a
					
				| 
						 | 
				
			
			@ -146,14 +146,6 @@ data:
 | 
			
		|||
  extra: YmFyCg==
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
When creating a `Pod`, Kubernetes automatically creates a service account Secret
 | 
			
		||||
and automatically modifies your Pod to use this Secret. The service account token
 | 
			
		||||
Secret contains credentials for accessing the API.
 | 
			
		||||
 | 
			
		||||
The automatic creation and use of API credentials can be disabled or
 | 
			
		||||
overridden if desired. However, if all you need to do is securely access the
 | 
			
		||||
API server, this is the recommended workflow.
 | 
			
		||||
 | 
			
		||||
See the [ServiceAccount](/docs/tasks/configure-pod-container/configure-service-account/)
 | 
			
		||||
documentation for more information on how service accounts work.
 | 
			
		||||
You can also check the `automountServiceAccountToken` field and the
 | 
			
		||||
| 
						 | 
				
			
			@ -161,6 +153,19 @@ You can also check the `automountServiceAccountToken` field and the
 | 
			
		|||
[`Pod`](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#pod-v1-core)
 | 
			
		||||
for information on referencing service account from Pods.
 | 
			
		||||
 | 
			
		||||
{{< note >}}
 | 
			
		||||
Automatic creation of API credentials in secrets to mount into running pods
 | 
			
		||||
is no longer used in v1.22 and newer versions. Instead, API credentials are 
 | 
			
		||||
obtained directly by using the [TokenRequest](/docs/reference/kubernetes-api/authentication-resources/token-request-v1/) API,
 | 
			
		||||
and are mounted into Pods using a [projected volume](/docs/reference/access-authn-authz/service-accounts-admin/#bound-service-account-token-volume).
 | 
			
		||||
The tokens obtained using this method have bounded lifetimes, and are automatically
 | 
			
		||||
invalidated when the Pod they are mounted into is deleted.
 | 
			
		||||
 | 
			
		||||
Service account token secrets can still be created manually if you need a token that never expires,
 | 
			
		||||
However, using the [TokenRequest](/docs/reference/kubernetes-api/authentication-resources/token-request-v1/)
 | 
			
		||||
API to obtain a token to access the API is recommended instead.
 | 
			
		||||
{{< /note >}}
 | 
			
		||||
 | 
			
		||||
### Docker config Secrets
 | 
			
		||||
 | 
			
		||||
You can use one of the following `type` values to create a Secret to
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -86,12 +86,36 @@ The output is similar to this:
 | 
			
		|||
 | 
			
		||||
### Without kubectl proxy
 | 
			
		||||
 | 
			
		||||
Use `kubectl describe secret...` to get the token for the default service account with grep/cut:
 | 
			
		||||
Use `kubectl apply` and `kubectl describe secret...` to create a token for the default service account with grep/cut:
 | 
			
		||||
 | 
			
		||||
First, create the Secret, requesting a token for the default ServiceAccount:
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
kubectl apply -f - <<EOF
 | 
			
		||||
apiVersion: v1
 | 
			
		||||
kind: Secret
 | 
			
		||||
metadata:
 | 
			
		||||
  name: default-token
 | 
			
		||||
  annotations:
 | 
			
		||||
    kubernetes.io/service-account.name: default
 | 
			
		||||
type: kubernetes.io/service-account-token
 | 
			
		||||
EOF
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Next, wait for the token controller to populate the Secret with a token:
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
while ! kubectl describe secret default-token | grep -E '^token' >/dev/null; do
 | 
			
		||||
  echo "waiting for token..." >&2
 | 
			
		||||
  sleep 1
 | 
			
		||||
done
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Capture and use the generated token:
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
APISERVER=$(kubectl config view --minify | grep server | cut -f 2- -d ":" | tr -d " ")
 | 
			
		||||
SECRET_NAME=$(kubectl get secrets | grep ^default | cut -f1 -d ' ')
 | 
			
		||||
TOKEN=$(kubectl describe secret $SECRET_NAME | grep -E '^token' | cut -f2 -d':' | tr -d " ")
 | 
			
		||||
TOKEN=$(kubectl describe secret default-token | grep -E '^token' | cut -f2 -d':' | tr -d " ")
 | 
			
		||||
 | 
			
		||||
curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
 | 
			
		||||
```
 | 
			
		||||
| 
						 | 
				
			
			@ -117,8 +141,7 @@ Using `jsonpath`:
 | 
			
		|||
 | 
			
		||||
```shell
 | 
			
		||||
APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
 | 
			
		||||
SECRET_NAME=$(kubectl get serviceaccount default -o jsonpath='{.secrets[0].name}')
 | 
			
		||||
TOKEN=$(kubectl get secret $SECRET_NAME -o jsonpath='{.data.token}' | base64 --decode)
 | 
			
		||||
TOKEN=$(kubectl get secret default-token -o jsonpath='{.data.token}' | base64 --decode)
 | 
			
		||||
 | 
			
		||||
curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
 | 
			
		||||
```
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,8 +95,25 @@ export CLUSTER_NAME="some_server_name"
 | 
			
		|||
# Point to the API server referring the cluster name
 | 
			
		||||
APISERVER=$(kubectl config view -o jsonpath="{.clusters[?(@.name==\"$CLUSTER_NAME\")].cluster.server}")
 | 
			
		||||
 | 
			
		||||
# Gets the token value
 | 
			
		||||
TOKEN=$(kubectl get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='default')].data.token}"|base64 --decode)
 | 
			
		||||
# Create a secret to hold a token for the default service account
 | 
			
		||||
kubectl apply -f - <<EOF
 | 
			
		||||
apiVersion: v1
 | 
			
		||||
kind: Secret
 | 
			
		||||
metadata:
 | 
			
		||||
  name: default-token
 | 
			
		||||
  annotations:
 | 
			
		||||
    kubernetes.io/service-account.name: default
 | 
			
		||||
type: kubernetes.io/service-account-token
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
# Wait for the token controller to populate the secret with a token:
 | 
			
		||||
while ! kubectl describe secret default-token | grep -E '^token' >/dev/null; do
 | 
			
		||||
  echo "waiting for token..." >&2
 | 
			
		||||
  sleep 1
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# Get the token value
 | 
			
		||||
TOKEN=$(kubectl get secret default-token -o jsonpath='{.data.token}' | base64 --decode)
 | 
			
		||||
 | 
			
		||||
# Explore the API with TOKEN
 | 
			
		||||
curl -X GET $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
 | 
			
		||||
| 
						 | 
				
			
			@ -119,26 +136,6 @@ The output is similar to this:
 | 
			
		|||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Using `jsonpath` approach:
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
 | 
			
		||||
TOKEN=$(kubectl get secret $(kubectl get serviceaccount default -o jsonpath='{.secrets[0].name}') -o jsonpath='{.data.token}' | base64 --decode )
 | 
			
		||||
curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
 | 
			
		||||
{
 | 
			
		||||
  "kind": "APIVersions",
 | 
			
		||||
  "versions": [
 | 
			
		||||
    "v1"
 | 
			
		||||
  ],
 | 
			
		||||
  "serverAddressByClientCIDRs": [
 | 
			
		||||
    {
 | 
			
		||||
      "clientCIDR": "0.0.0.0/0",
 | 
			
		||||
      "serverAddress": "10.0.1.149:443"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The above example uses the `--insecure` flag. This leaves it subject to MITM
 | 
			
		||||
attacks. When kubectl accesses the cluster it uses a stored root certificate
 | 
			
		||||
and client certificates to access the server. (These are installed in the
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue