OIDC 인증에 Kubernetes 사용하기
OIDC 인증에 Kubernetes 사용하기
Kubernetes는 OIDC 프로바이더로 작동할 수 있어, Vault가 JWT/OIDC 인증으로 그 서비스 계정 토큰을 검증할 수 있어요.
참고: JWT 인증 엔진은 인증 중 Kubernetes의 TokenReview API를 사용하지 않고, 공개 키 암호로 JWT 내용을 검증해요. 즉 Kubernetes가 폐기한 토큰도 만료 시간까지 Vault가 여전히 유효한 것으로 간주해요. 이 위험을 완화하려면 서비스 계정 토큰에 짧은 TTL을 사용하거나, 실제로 TokenReview API를 사용하는 Kubernetes 인증을 사용하세요.
출처: 문서
본문
서비스 계정 발급자 디스커버리 사용하기
서비스 계정 발급자 디스커버리를 사용하면 JWT 인증 마운트에 OIDC discovery URL만 제공하면 되고, 때로는 신뢰할 TLS 인증 기관을 제공하면 돼요. Kubernetes 클러스터가 요구 사항을 충족한다면 구성하기 가장 간단한 방법이에요.
Kubernetes 클러스터 요구 사항:
ServiceAccountIssuerDiscovery기능 활성화. 1.18부터 제공되며 1.20부터 기본 활성화.- kube-apiserver의
--service-account-issuer플래그가 Vault에서 도달 가능한 URL로 설정. 대부분의 관리형 Kubernetes 솔루션에서 기본적으로 공개. - 로그인 시 단기 서비스 계정 토큰을 사용해야 함. 1.21부터 파드에 마운트된 토큰의 기본은 단기.
구성 단계:
- OIDC discovery URL이 인증을 요구하지 않는지 확인합니다(여기에 자세히 설명).
kubectl create clusterrolebinding oidc-reviewer \
--clusterrole=system:service-account-issuer-discovery \
--group=system:unauthenticated
- 클러스터의 발급자 URL을 찾습니다.
ISSUER="$(kubectl get --raw /.well-known/openid-configuration | jq -r '.issuer')"
- Vault에서 JWT 인증을 활성화하고 구성합니다.
- Vault가 Kubernetes에서 실행 중인 경우:
kubectl exec vault-0 -- vault auth enable jwt
kubectl exec vault-0 -- vault write auth/jwt/config \
oidc_discovery_url=https://kubernetes.default.svc.cluster.local \
oidc_discovery_ca_pem=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
- 또는 Vault가 Kubernetes에서 실행 중이 아닌 경우:
참고: Vault가 클러스터 밖에 있을 때 아래의
$ISSUER엔드포인트에 도달할 수도 있고 아닐 수도 있어요. 도달할 수 없다면jwt_validation_pubkeys로 JWT 인증을 구성할 수 있어요.
vault auth enable jwt
vault write auth/jwt/config oidc_discovery_url="${ISSUER}"
- 아래에 자세히 설명된 대로 역할을 구성하고 로그인합니다.
JWT 검증 공개 키 사용하기
이 방법은 Vault에서 Kubernetes API에 도달할 수 없거나, 공개 서명 키를 연결해 단일 JWT 인증 마운트가 여러 Kubernetes 클러스터를 서비스하길 원할 때 유용해요.
Kubernetes에서 JWT Signing Key 회전: Kubernetes가 사용하는 JWT Signing Key가 회전되면 새 키로 이 과정을 반복해야 해요.
Kubernetes 클러스터 요구 사항:
ServiceAccountIssuerDiscovery기능 활성화. 1.18부터 제공되며 1.20부터 기본 활성화.- Kubernetes 마스터 노드에 접근할 수 있어
/etc/kubernetes/pki/sa.pub에서 디스크의 공개 서명 키를 직접 읽을 수 있으면 이 요구 사항을 피할 수 있어요. 이 경우 키를 검색하고 변환하는 단계를 건너뛸 수 있는데, 이미 PEM 형식이기 때문이에요.
- Kubernetes 마스터 노드에 접근할 수 있어
- 로그인 시 단기 서비스 계정 토큰을 사용해야 함. 1.21부터 파드에 마운트된 토큰의 기본은 단기.
구성 단계:
- 클러스터의 JWKS URI에서 서비스 계정 서명 공개 키를 가져옵니다.
# Query the jwks_uri specified in /.well-known/openid-configuration
kubectl get --raw "$(kubectl get --raw /.well-known/openid-configuration | jq -r '.jwks_uri' | sed -r 's/.*\.[^/]+(.*)/\1/')"
- 키를 JWK 형식에서 PEM으로 변환합니다. CLI 도구나 이것 같은 온라인 변환기를 사용할 수 있어요.
- JWT 인증 마운트를 그 공개 키로 구성합니다.
vault write auth/jwt/config \
jwt_validation_pubkeys="-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9...
-----END PUBLIC KEY-----","-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9...
-----END PUBLIC KEY-----"
- 아래에 자세히 설명된 대로 역할을 구성하고 로그인합니다.
역할 만들기와 로그인
JWT 인증 마운트가 구성되면 역할을 구성하고 로그인할 준비가 된 거예요. 다음은 기본적으로 모든 파드에서 사용할 수 있는 projected 서비스 계정 토큰을 사용한다고 가정해요. audience 또는 TTL을 제어하려면 TTL 및 audience 지정을 참고하세요.
- 기본 audiences 배열에서 값을 하나 선택합니다. 이 예시들에서
aud배열에는https://kubernetes.default.svc.cluster.local한 개만 있어요.
기본 audiences를 찾으려면 새 토큰을 만들거나(kubectl v1.24.0+ 필요):
$ kubectl create token default | cut -f2 -d. | base64 --decode
{"aud":["https://kubernetes.default.svc.cluster.local"], ... "sub":"system:serviceaccount:default:default"}
실행 중인 파드의 파일시스템에서 토큰을 읽습니다:
$ kubectl exec my-pod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -f2 -d. | base64 --decode
{"aud":["https://kubernetes.default.svc.cluster.local"], ... "sub":"system:serviceaccount:default:default"}
default네임스페이스의default서비스 계정이 사용할 수 있는 JWT 인증용 역할을 만듭니다.
vault write auth/jwt/role/my-role \
role_type="jwt" \
bound_audiences="<AUDIENCE-FROM-PREVIOUS-STEP>" \
user_claim="sub" \
bound_subject="system:serviceaccount:default:default" \
policies="default" \
ttl="1h"
- 서비스 계정 JWT에 접근할 수 있는 파드나 다른 클라이언트는 이제 로그인할 수 있어요.
vault write auth/jwt/login \
role=my-role \
jwt=@/var/run/secrets/kubernetes.io/serviceaccount/token
# OR equivalent to:
curl \
--fail \
--request POST \
--header "X-Vault-Request: true" \
--data '{"jwt":"<JWT-TOKEN-HERE>","role":"my-role"}' \
"${VAULT_ADDR}/v1/auth/jwt/login"
TTL 및 audience 지정하기
서비스 계정 토큰에 사용자 지정 TTL이나 audience를 지정하려면, 다음 파드 spec이 기본 admission 주입 토큰을 재정의하는 볼륨 마운트를 보여줘요. 이는 특히 kube-apiserver의 --service-account-extend-token-expiration 플래그를 비활성화할 수 없고 짧은 TTL을 사용하려 할 때 중요해요.
결과 토큰을 사용할 때 Vault의 JWT 인증 마운트에서 역할을 만들 때 bound_audiences=vault를 설정해야 해요.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
# automountServiceAccountToken is redundant in this example because the
# mountPath used overlaps with the default path. The overlap stops the default
# admission injected token from being created. You can use this option to
# ensure only a single token is mounted if you choose a different mount path.
automountServiceAccountToken: false
containers:
- name: nginx
image: nginx
volumeMounts:
- name: custom-token
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
volumes:
- name: custom-token
projected:
defaultMode: 420
sources:
- serviceAccountToken:
path: token
expirationSeconds: 600 # 10 minutes is the minimum TTL
audience: vault # Must match your JWT role's `bound_audiences`
# The remaining sources are included to mimic the rest of the default
# admission injected volume.
- configMap:
name: kube-root-ca.crt
items:
- key: ca.crt
path: ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
더 알아보기 (Learn more)
- Vault JWT/OIDC 인증 방식에 대한 자세한 내용은 JWT 인증 방식 문서를 참고하세요.
- Kubernetes 서비스 계정 발급자 디스커버리에 대한 자세한 내용은 Kubernetes 문서를 참고하세요.