在 GKE (.NET) 中使用 Workload Identity 时无法获取访问令牌

问题描述 投票:0回答:4

我已在 GKE 集群上设置了工作负载身份,现在我使用链接到具有适当权限的 IAM SA 的 Kubernetes SA。我检查过,当我使用 IAM SA 密钥文件时,它会获得我需要的访问权限。

但是,即使遵循 docs,它也会变得奇怪。

第一个建议的检查是运行此命令来检查元数据服务器响应:

$ curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email

<sa_name>@<project_id>.iam.gserviceaccount.com

到目前为止,一切都很好。描述使用“配额项目”选项的下一段建议使用另一个命令,该命令应返回身份令牌。结果失败了:

$ curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token

Unable to generate access token; IAM returned 404 Not Found: Not found; Gaia id not found for email <sa_name>@<project_id>.iam.gserviceaccount.com

当我使用 .NET SDK 并调用此命令时,也会发生同样的情况:

var oidcToken1 = await cc.GetOidcTokenAsync(
    OidcTokenOptions.FromTargetAudience(_serviceUrl),
    cancellationToken
);

_addToken = async (request, token) => {
    request.Headers.Authorization = new AuthenticationHeaderValue(
        "Bearer",
        await oidcToken1.GetAccessTokenAsync(cancellationToken: token)
    );
};

当我使用 IAM SA JSON 密钥时,代码工作正常,但是当它在使用工作负载身份的 pod 中运行时,我收到与之前相同的消息:

Google.Apis.Auth.OAuth2.ServiceCredential Token has expired, trying to get a new one.
Google.Apis.Http.ConfigurableMessageHandler Request[00000001] (triesRemaining=3) URI: 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://<service_url>&format=full'
Google.Apis.Http.ConfigurableMessageHandler Response[00000001] Response status: NotFound 'Not Found'
Google.Apis.Http.ConfigurableMessageHandler Response[00000001] An abnormal response wasn't handled. Status code is NotFound

当我使用 Workload Identity 测试容器中的

gcloud auth application-default print-access-token
时,也会发生同样的情况:

错误:(gcloud.auth.application-default.print-access-token)刷新当前身份验证令牌时出现问题:(“无法检索http://metadata.google.internal/computeMetadata/v1/instance/ service-accounts/@.iam.gserviceaccount.com/token?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform 来自 Google 计算引擎元数据服务。状态:404 响应: b'无法生成访问令牌; IAM返回404 Not Found:未找到;找不到电子邮件 @.iam.gserviceaccount.com 的 Gaia ID '”,

我不知道还能做什么;似乎整件事都行不通。

google-cloud-platform google-kubernetes-engine google-api-dotnet-client
4个回答
1
投票

我找到了。我犯了一个愚蠢的错误,输错了 Kubernetes 服务账户注释中配置的 IAM 服务账户名称。

Google 支持提供了故障排除指南,我遵循了这些指南,并且重要的是使用上一个命令的输出作为下一个命令的输入(如果适用)。当我尝试使用 Kubernetes 服务帐户注释中的值描述 IAM 服务帐户时,出现“SA not found”错误,这为我提供了解决问题的线索。


0
投票

我怀疑你要么配置错误了一个步骤(服务帐户的东西特别粗糙),要么你遇到了车祸

我无法重现您的问题。它对我有用。

BILLING="[YOUR-BILLING-ACCOUNT]"

Q="74552713"
PROJECT=$(whoami)-$(date +%y%m%d)-${Q}

gcloud projects create ${PROJECT}

gcloud beta billing projects link ${PROJECT} \
--billing-account=${BILLING}

gcloud services enable container.googleapis.com \
--project=${PROJECT}

POOL="${PROJECT}.svc.id.goog"

CLUSTER_PROJECT="${PROJECT}"
CLUSTER_NAME="cluster"
CLUSTER_LOCATION="us-west1-c"

# Gets the latest RAPID version
CLUSTER_VERSION=$(\
  gcloud container get-server-config \
  --project=${PROJECT} \
  --zone=${CLUSTER_LOCATION} \
  --flatten=channels \
  --filter=channels.channel=RAPID \
  --format="value(channels.validVersions[0])")

# My go-to test cluster config w/ workload-pool
gcloud beta container clusters create ${CLUSTER_NAME} \
--spot \
--no-enable-basic-auth \
--cluster-version=${CLUSTER_VERSION} \
--release-channel="rapid" \
--machine-type="e2-standard-2" \
--image-type="COS_CONTAINERD" \
--metadata=disable-legacy-endpoints=true \
--num-nodes=1 \
--addons=HorizontalPodAutoscaling,HttpLoadBalancing,GcePersistentDiskCsiDriver \
--enable-ip-alias \
--enable-autoupgrade \
--enable-autorepair \
--enable-managed-prometheus \
--enable-shielded-nodes \
--enable-vertical-pod-autoscaling \
--shielded-secure-boot \
--shielded-integrity-monitoring \
--no-enable-master-authorized-networks \
--max-surge-upgrade=1 \
--max-unavailable-upgrade=0 \
--node-locations=${CLUSTER_LOCATION} \
--zone=${CLUSTER_LOCATION} \
--project=${CLUSTER_PROJECT} \
--workload-pool=${POOL}

# Implicit
# gcloud container clusters get-credentials ${CLUSTER_NAME} ...

# Test that cluster's workloadPool matches expected value
GOT=$(\
  gcloud container clusters describe ${CLUSTER_NAME} \
  --zone=${CLUSTER_LOCATION} \
  --project=${CLUSTER_PROJECT} \
  --format="value(workloadIdentityConfig.workloadPool)")

WANT="${POOL}"
[ "${GOT}" == "${WANT}" ] && echo "true" || echo "false"

# Kubernetes == Google Cloud Service Account name
ACCOUNT="tester"

EMAIL="${ACCOUNT}@${PROJECT}.iam.gserviceaccount.com"

NAMESPACE="${Q}"

kubectl create namespace ${NAMESPACE}

kubectl create serviceaccount ${ACCOUNT} \
--namespace=${NAMESPACE}

gcloud iam service-accounts create ${ACCOUNT} \
--project=${PROJECT}

# Redundant for the purpose of this test
ROLE="roles/cloudprofiler.agent"
gcloud projects add-iam-policy-binding ${PROJECT} \
--member="serviceAccount:${EMAIL}" \
--role="${ROLE}"

# Allow Kubernetes robot to impersonate Cloud robot
gcloud iam service-accounts add-iam-policy-binding ${EMAIL} \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:${PROJECT}.svc.id.goog[${NAMESPACE}/${ACCOUNT}]"

# Updated IAM policy for serviceAccount [{EMAIL}].
# bindings:
# - members:
#   - serviceAccount:{PROJECT}.svc.id.goog[{NAMESPACE}/{ACCOUNT}]
#   role: roles/iam.workloadIdentityUser
# etag: BwXuOwsx9lk=
# version: 1

# Annotate Service Account
kubectl annotate serviceaccount ${ACCOUNT} \
--namespace=${NAMESPACE} \
iam.gke.io/gcp-service-account=${EMAIL}

# Update Pod specs
# spec:
#   serviceAccountName: {ACCOUNT}
#   nodeSelector:
#     iam.gke.io/gke-metadata-server-enabled: "true"


POD="workload-identity-test"

echo "
apiVersion: v1
kind: Pod
metadata:
  name: \"${POD}\"
  namespace: \"${NAMESPACE}\"
spec:
  containers:
  - image: google/cloud-sdk:slim
    name: \"${POD}\"
    command: [\"sleep\",\"infinity\"]
  serviceAccountName: \"${ACCOUNT}\"
  nodeSelector:
    iam.gke.io/gke-metadata-server-enabled: \"true\"
" | kubectl apply --filename=-


# Test that proxied (!) Metadata Service Account email matches
GOT=$(\
  kubectl exec \
  --stdin --tty \
  ${POD} \
  --namespace=${NAMESPACE} \
  -- /bin/bash -c 'curl --header "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email')

WANT="${EMAIL}"
[ "${GOT}" == "${WANT}" ] && echo "true" || echo "false"

# Demonstrate that access-token is obtained
kubectl exec \
--stdin --tty \
${POD} \
--namespace=${NAMESPACE} \
-- /bin/bash -c 'curl --header "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token' \
| jq -r .access_token[0:15]
# ya29.c.b0Aa9Vdy


0
投票

除了前面提到的问题之外,还有一项额外的检查(只是为了补充其他答案),我建议非常小心地命名 Kubernetes 服务帐户定义与实际服务帐户名称。

在实现此操作时,我们在 GCP 上将服务帐户命名为 GSA_NAME=

team-api
,Kubernetes 定义命名为 KSA_NAME=
team-api-svc-ac

我们最终将政策定义为

gcloud iam service-accounts add-iam-policy-binding GSA_NAME@GSA_PROJECT.iam.gserviceaccount.com \
    --role roles/iam.workloadIdentityUser \
    --member "serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/GSA_NAME]"

当它应该是:

gcloud iam service-accounts add-iam-policy-binding GSA_NAME@GSA_PROJECT.iam.gserviceaccount.com \
    --role roles/iam.workloadIdentityUser \
    --member "serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]"

您可以查看此示例的文档,但这是我们可以深入了解细节的步骤之一。


0
投票

我在尝试使用不存在的服务帐户时遇到了此问题,请仔细检查您的服务帐户电子邮件,确保没有拼写错误。

© www.soinside.com 2019 - 2024. All rights reserved.