kubectl patch secret with bash gcloud identity-token, heredoc 和 printf
kubectl patch secret with bash gcloud identity-token, heredoc and printf
我想创建一个简单的 k8s cronjob 来保密地保持 gcp 身份令牌新鲜。
一个比较简单的问题,我无法解决
给出
kubectl patch secret token-test --type json -p=<< END
[
{
"op": "replace",
"path": "/data/token.jwt",
"value": "$(gcloud auth print-identity-token | base64 )"
}
]
END
我希望将此应用于 kubectl patch secret token-test --type json -p=$(printf "'%s'" "$json")
我尝试了很多变体,奇怪的是,如果我粘贴 printf 的 heredoc insted 结果,它就会起作用。但是我所有的努力都失败了(还尝试了 json 单行文档)
$ kubectl patch secret token-test --type json -p=$(printf "'%s'" "$json")
error: unable to parse "'[{": yaml: found unexpected end of stream
而这确实有效:
printf "'%s'" "$json"|pbcopy
kubectl patch secret sudo-token-test --type json -p '[{ "op": "replace","path": "/data/token.jwt","value": "ZX...Zwo="}]'
secret/token-test patched
我无法理解失败时有什么不同。我知道 bash 在字符串处理方面有点棘手,但我不确定这是 bash 问题还是 kubectl 中的问题。
$ json='[{ "op": "replace","path": "/data/token.jwt","value": "'"$(gcloud auth print-identity-token | base64 )"'"}]'
$ kubectl patch secret token-test --type json -p="$json"
secret/token-test patched
通过在 heredoc 中附加插值字符串,问题得到解决。
仍然不知道为什么其他方法失败了。
编辑:
最终结果是放弃 kubectl 并改用 curl,因为它更适合 docker 图像。
# Point to the internal API server hostname
APISERVER=https://kubernetes.default.svc
# Path to ServiceAccount token
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
# Read this Pod's namespace
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
# Read the ServiceAccount bearer token
TOKEN=$(cat ${SERVICEACCOUNT}/token)
# Reference the internal certificate authority (CA)
CACERT=${SERVICEACCOUNT}/ca.crt
SECRET_NAME=$(cat /etc/scripts/secret-name)
# Explore the API with TOKEN
curl --fail --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" --request PATCH ${APISERVER}/api/v1/namespaces/${NAMESPACE}/secrets/${SECRET_NAME} \
-H 'Accept: application/json' \
-H "Content-Type: application/json-patch+json" \
-d '[{ "op": "replace","path": "/data/token.jwt","value": "'"$(gcloud auth print-identity-token | base64 -w0 )"'"}]' \
--output /dev/null
正如我在 DazWilkin 回答中的评论,调用 gcloud auth print-identity-token
的用户实际上是 k8s 上的服务帐户,通过 GKE 上的工作负载身份验证到 GCP ServiceAccount。
我需要令牌才能在不存储实际凭据的情况下调用 AWS,方法是使用它通过 Workload Identity Federation 调用 AWS
这是一种略有不同的方法,但是,怎么样:
printf "foo" > test
kubectl create secret generic freddie \
--namespace=default \
--from-file=./test
kubectl get secret/freddie \
--namespace=default \
--output=jsonpath="{.data.test}" \
| base64 --decode
foo
X="$(printf "bar" | base64)"
kubectl patch secret/freddie \
--namespace=default \
--patch="{\"data\":{\"test\":\"${X}\"}}"
kubectl get secret/freddie \
--namespace=default \
--output=jsonpath="{.data.test}" \
| base64 --decode
bar
NOTE it's not a best practice to use your user (gcloud auth print-identity-token
) credentials in this way. Service Accounts are preferred. Service Accounts are intended for machine (rather than a human) auth and they can be more easily revoked.
User credentials grant the bearer all the powers of the user account (and this is likely extensive).
There's a portable alternative in which you create a Kubernetes secret from a Service Account key:
kubectl create secret generic your-key \
--from-file=your-key.json=/path/to/your-key.json
There's a cool-kids who use GKE-mostly approach called Workload Identity
我想创建一个简单的 k8s cronjob 来保密地保持 gcp 身份令牌新鲜。
一个比较简单的问题,我无法解决
给出
kubectl patch secret token-test --type json -p=<< END
[
{
"op": "replace",
"path": "/data/token.jwt",
"value": "$(gcloud auth print-identity-token | base64 )"
}
]
END
我希望将此应用于 kubectl patch secret token-test --type json -p=$(printf "'%s'" "$json")
我尝试了很多变体,奇怪的是,如果我粘贴 printf 的 heredoc insted 结果,它就会起作用。但是我所有的努力都失败了(还尝试了 json 单行文档)
$ kubectl patch secret token-test --type json -p=$(printf "'%s'" "$json")
error: unable to parse "'[{": yaml: found unexpected end of stream
而这确实有效:
printf "'%s'" "$json"|pbcopy
kubectl patch secret sudo-token-test --type json -p '[{ "op": "replace","path": "/data/token.jwt","value": "ZX...Zwo="}]'
secret/token-test patched
我无法理解失败时有什么不同。我知道 bash 在字符串处理方面有点棘手,但我不确定这是 bash 问题还是 kubectl 中的问题。
$ json='[{ "op": "replace","path": "/data/token.jwt","value": "'"$(gcloud auth print-identity-token | base64 )"'"}]'
$ kubectl patch secret token-test --type json -p="$json"
secret/token-test patched
通过在 heredoc 中附加插值字符串,问题得到解决。 仍然不知道为什么其他方法失败了。
编辑:
最终结果是放弃 kubectl 并改用 curl,因为它更适合 docker 图像。
# Point to the internal API server hostname
APISERVER=https://kubernetes.default.svc
# Path to ServiceAccount token
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
# Read this Pod's namespace
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
# Read the ServiceAccount bearer token
TOKEN=$(cat ${SERVICEACCOUNT}/token)
# Reference the internal certificate authority (CA)
CACERT=${SERVICEACCOUNT}/ca.crt
SECRET_NAME=$(cat /etc/scripts/secret-name)
# Explore the API with TOKEN
curl --fail --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" --request PATCH ${APISERVER}/api/v1/namespaces/${NAMESPACE}/secrets/${SECRET_NAME} \
-H 'Accept: application/json' \
-H "Content-Type: application/json-patch+json" \
-d '[{ "op": "replace","path": "/data/token.jwt","value": "'"$(gcloud auth print-identity-token | base64 -w0 )"'"}]' \
--output /dev/null
正如我在 DazWilkin 回答中的评论,调用 gcloud auth print-identity-token
的用户实际上是 k8s 上的服务帐户,通过 GKE 上的工作负载身份验证到 GCP ServiceAccount。
我需要令牌才能在不存储实际凭据的情况下调用 AWS,方法是使用它通过 Workload Identity Federation 调用 AWS
这是一种略有不同的方法,但是,怎么样:
printf "foo" > test
kubectl create secret generic freddie \
--namespace=default \
--from-file=./test
kubectl get secret/freddie \
--namespace=default \
--output=jsonpath="{.data.test}" \
| base64 --decode
foo
X="$(printf "bar" | base64)"
kubectl patch secret/freddie \
--namespace=default \
--patch="{\"data\":{\"test\":\"${X}\"}}"
kubectl get secret/freddie \
--namespace=default \
--output=jsonpath="{.data.test}" \
| base64 --decode
bar
NOTE it's not a best practice to use your user (
gcloud auth print-identity-token
) credentials in this way. Service Accounts are preferred. Service Accounts are intended for machine (rather than a human) auth and they can be more easily revoked.User credentials grant the bearer all the powers of the user account (and this is likely extensive).
There's a portable alternative in which you create a Kubernetes secret from a Service Account key:
kubectl create secret generic your-key \ --from-file=your-key.json=/path/to/your-key.json
There's a cool-kids who use GKE-mostly approach called Workload Identity