VSO 인증

VSO 인증 (Vault authentication)

VaultAuth 리소스와 VaultAuthGlobal 글로벌 구성을 사용해 VSO가 Vault에 인증하는 방법을 다룹니다.

출처: 문서

본문

인증 구성 (Auth configuration)

Vault Secrets Operator(VSO)는 VaultAuth 리소스에 의존해 Vault에 인증해요. 인증에 필요한 자격 증명을 생성하는 자격 증명 제공자(credential provider) 에 의존합니다. 예를 들어 VSO가 kubernetes 인증 백엔드에 인증할 때, VaultAuth 리소스에 정의된 kubernetes 인증 방식에 구성된 쿠버네티스 서비스 어카운트로 토큰을 생성합니다. 서비스 어카운트는 요청 리소스의 쿠버네티스 네임스페이스에 구성되어야 해요. 즉 VaultStaticSecret 같은 리소스가 apps 네임스페이스에 만들어지면, 서비스 어카운트도 apps 네임스페이스에 있어야 합니다. 이 접근 방식의 근거는 크로스 네임스페이스 접근이 불가능하게 하기 위해서예요.

Vault 인증 글로벌 (Vault authentication globals)

VaultAuthGlobal 리소스는 일련의 VaultAuth 리소스에 걸쳐 단일 인증 구성을 공유할 수 있게 해주는 전역 구성이에요. 이는 같은 기본 구성을 공유하는 VaultAuth 리소스가 여러 개 있을 때 유용합니다. 예를 들어 모두 같은 인증 백엔드로 Vault에 인증하는 VaultAuth 리소스가 여러 개 있다면, 모든 VaultAuth 인스턴스에 공통인 구성을 정의하는 단일 VaultAuthGlobal 리소스를 만들 수 있어요. mount, method, namespace, 방식별 구성 같은 옵션은 모두 VaultAuthGlobal 리소스에서 상속할 수 있습니다. VaultAuth 리소스의 어떤 필드든 VaultAuthGlobal 인스턴스에서 상속할 수 있어요. 일반적으로 role 같은 필드와 serviceAccount 같은 자격 증명 제공자별 필드는 VaultAuthGlobal보다는 해당 VaultAuth 인스턴스에 설정하는데, VaultAuth 리소스가 필요한 애플리케이션에 더 특정적이기 때문이에요.

전체 필드 목록은 VaultAuthGlobal specVaultAuth spec을 참고하세요.

VaultAuthGlobal 구성 상속

  • VaultAuth 리소스의 구성이 VaultAuthGlobal 리소스의 구성보다 우선해요.
  • VaultAuthGlobal은 어떤 네임스페이스에든 있을 수 있지만, VaultAuth 리소스의 네임스페이스가 참조할 수 있게 해야 해요.
  • 기본 값인 default 라는 이름의 VaultAuthGlobal 리소스는, spec.vaultAuthGlobalRef.allowDefault가 true로 설정되고 VSO가 -global-vault-auth-options 플래그에 allow-default-globals 옵션(기본값)으로 실행 중일 때 모든 VaultAuth 리소스에서 자동으로 참조됩니다.
  • spec.vaultAuthGlobalRef.namespace가 설정되면 default VaultAuthGlobal 리소스 검색이 그 네임스페이스로 제한돼요. 그렇지 않으면 검색 순서는:
    1. 참조하는 VaultAuth 리소스의 네임스페이스에 있는 default VaultAuthGlobal 리소스.
    2. Operator의 네임스페이스에 있는 default VaultAuthGlobal 리소스.

샘플 사용 사례와 구성

다음 섹션은 VaultAuthGlobal 리소스의 샘플 사용 사례와 구성을 제공해요. 이 예제들은 VaultAuthGlobal 리소스를 사용해 일련의 VaultAuth 리소스에 걸쳐 공통 인증 구성을 공유하는 방법을 보여줘요. 다른 네임스페이스 VSO 커스텀 리소스 정의처럼, 단일 쿠버네티스 클러스터에 여러 VaultAuthGlobal 리소스를 구성할 수 있습니다.

공유 인증 백엔드를 사용하는 여러 애플리케이션

Vault 관리자가 kubernetes에 마운트된 Vault의 쿠버네티스 인증 백엔드를 구성했다고 해요. 관리자는 두 애플리케이션이 각자의 역할과 서비스 어카운트로 인증하길 기대합니다. 관리자는 애플리케이션의 서비스 어카운트와 네임스페이스에 바인딩된 Vault의 필요한 역할을 만듭니다.

관리자는 다음 구성으로 default VaultAuthGlobal을 만듭니다.

---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuthGlobal
metadata:
  name: default
  namespace: admin
spec:
  allowedNamespaces:
    - apps
  defaultAuthMethod: kubernetes
  kubernetes:
    audiences:
    - vault
    mount: kubernetes
    role: default
    serviceAccount: default
    tokenExpirationSeconds: 600

개발자는 애플리케이션 네임스페이스에 다음 구성을 가진 VaultAuth와 VaultStaticSecret 리소스를 만듭니다.

애플리케이션 1은 이렇게 구성됩니다.

---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
  name: app1
  namespace: apps
spec:
  kubernetes:
    role: app1
    serviceAccount: app1
  vaultAuthGlobalRef:
    allowDefault: true
    namespace: admin
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
  name: app1-secret
  namespace: apps
spec:
  destination:
    create: true
    name: app1-secret
  hmacSecretData: true
  mount: apps
  path: app1
  type: kv-v2
  vaultAuthRef: app1

애플리케이션 2는 비슷한 구성을 가집니다.

---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
  name: app2
  namespace: apps
spec:
  kubernetes:
    role: app2
    serviceAccount: app2
  vaultAuthGlobalRef:
    allowDefault: true
    namespace: admin
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
  name: app2-secret
  namespace: apps
spec:
  destination:
    create: true
    name: app2-secret
  hmacSecretData: true
  mount: apps
  path: app2
  type: kv-v2
  vaultAuthRef: app2

설명

  • default VaultAuthGlobal 리소스가 admin 네임스페이스에 만들어져요. 이 리소스는 참조하는 모든 VaultAuth 리소스에 공통 구성을 정의합니다. allowedNamespaces 필드는 이 VaultAuthGlobal 리소스를 참조할 수 있는 VaultAuth 리소스를 제한합니다. 이 경우 apps 네임스페이스의 리소스만 이 VaultAuthGlobal 리소스를 참조할 수 있어요.
  • apps 네임스페이스의 VaultAuth 리소스가 VaultAuthGlobal 리소스를 참조합니다. 이를 통해 VaultAuth 리소스가 VaultAuthGlobal 리소스의 구성을 상속할 수 있어요. role과 serviceAccount 필드는 애플리케이션에 특정적이므로 VaultAuthGlobal 리소스에서 상속되지 않습니다. .spec.vaultAuthGlobalRef.allowDefault 필드가 true로 설정되어 있으므로 VaultAuth 리소스는 정의된 네임스페이스의 default VaultAuthGlobal을 자동으로 참조합니다.
  • apps 네임스페이스의 VaultStaticSecret 리소스가 VaultAuth 리소스를 참조합니다. 이를 통해 VaultStaticSecret 리소스가 Vault에 인증해 KV 시크릿을 대상 쿠버네티스 시크릿으로 동기화할 수 있어요.

공유 인증 백엔드와 역할을 사용하는 여러 애플리케이션

Vault 관리자가 kubernetes에 마운트된 Vault의 쿠버네티스 인증 백엔드를 구성했다고 해요. 관리자는 두 애플리케이션이 단일 역할과 서비스 어카운트로 인증하길 기대합니다. 관리자는 애플리케이션의 같은 서비스 어카운트와 네임스페이스에 바인딩된 Vault의 필요한 역할을 만듭니다.

관리자나 개발자는 애플리케이션 네임스페이스에 다음 구성으로 default VaultAuthGlobal을 만듭니다.

---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuthGlobal
metadata:
  name: default
  namespace: apps
spec:
  defaultAuthMethod: kubernetes
  kubernetes:
    audiences:
    - vault
    mount: kubernetes
    role: apps
    serviceAccount: apps
    tokenExpirationSeconds: 600

개발자는 애플리케이션 네임스페이스에 단일 VaultAuth와 필요한 VaultStatic 시크릿을 다음으로 만듭니다.

---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
  name: apps
  namespace: apps
spec:
  vaultAuthGlobalRef:
    allowDefault: true
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
  name: app1-secret
  namespace: apps
spec:
  destination:
    create: true
    name: app1-secret
  hmacSecretData: true
  mount: apps
  path: app1
  type: kv-v2
  vaultAuthRef: apps
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
  name: app2-secret
  namespace: apps
spec:
  destination:
    create: true
    name: app2-secret
  hmacSecretData: true
  mount: apps
  path: app2
  type: kv-v2
  vaultAuthRef: apps

설명

  • default VaultAuthGlobal 리소스가 apps 네임스페이스에 만들어져요. 참조하는 VaultAuth 리소스에 필요한 모든 구성을 제공합니다.
  • apps 네임스페이스에 단일 VaultAuth 리소스가 만들어져요. 이 리소스는 VaultAuthGlobal 리소스를 참조하고 그 구성을 상속합니다.
  • apps 네임스페이스의 VaultStaticSecret 리소스가 VaultAuth 리소스를 참조합니다. 이를 통해 VaultStaticSecret 리소스가 Vault에 인증해 KV 시크릿을 대상 쿠버네티스 시크릿으로 동기화할 수 있어요.

여러 인증 백엔드와 역할을 사용하는 여러 애플리케이션

Vault 관리자가 kubernetes에 마운트된 Vault의 쿠버네티스 인증 백엔드를 구성했다고 해요. 추가로 관리자가 jwt에 마운트된 JWT 인증 백엔드도 구성했습니다. 관리자는 각 인증 방식에 대한 Vault의 필요한 역할을 만듭니다. 두 애플리케이션 중 하나는 kubernetes 인증을, 다른 하나는 jwt 인증을 사용해 인증하길 기대합니다.

관리자나 개발자는 애플리케이션 네임스페이스에 다음 구성으로 default VaultAuthGlobal을 만듭니다.

---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuthGlobal
metadata:
  name: default
  namespace: apps
spec:
  defaultAuthMethod: kubernetes
  kubernetes:
    audiences:
    - vault
    mount: kubernetes
    role: apps
    serviceAccount: apps-k8s
    tokenExpirationSeconds: 600
  jwt:
    audiences:
    - vault
    mount: jwt
    role: apps
    serviceAccount: apps-jwt

개발자는 애플리케이션 네임스페이스에 다음 구성을 가진 VaultAuth와 VaultStaticSecret 리소스를 만듭니다.

애플리케이션 1은 kubernetes 인증 방식을 사용하는 구성입니다.

---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
  name: apps-default
  namespace: apps
spec:
  # VaultAuthGlobal .spec.defaultAuthMethod에 정의된
  # 기본 kubernetes 인증 방식을 사용
  vaultAuthGlobalRef:
    allowDefault: true
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
  name: app1-secret
  namespace: apps
spec:
  destination:
    create: true
    name: app1-secret
  hmacSecretData: true
  mount: apps
  path: app1
  type: kv-v2
  vaultAuthRef: apps-default

애플리케이션 2는 비슷한 구성이지만 JWT 인증 방식을 사용합니다.

---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
  name: apps-jwt
  namespace: apps
spec:
  method: jwt
  vaultAuthGlobalRef:
    allowDefault: true
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
  name: app2-secret
  namespace: apps
spec:
  destination:
    create: true
    name: app2-secret
  hmacSecretData: true
  mount: apps
  path: app2
  type: kv-v2
  vaultAuthRef: apps-jwt

설명

  • default VaultAuthGlobal 리소스가 apps 네임스페이스에 만들어져요. 참조하는 VaultAuth 리소스에 필요한 모든 구성을 제공합니다. defaultAuthMethod 필드는 Vault에 인증할 때 사용할 기본 인증 방식을 정의해요. kubernetes와 jwt 필드는 각 인증 방식의 구성을 정의합니다.
  • 애플리케이션 1은 VaultAuthGlobal 리소스에 정의된 기본 kubernetes 인증 방식을 사용해요. VaultAuth 리소스는 VaultAuthGlobal 리소스를 참조하고 그 kubernetes 인증 구성을 상속합니다.
  • 애플리케이션 2는 VaultAuthGlobal 리소스에 정의된 JWT 인증 방식을 사용해요. VaultAuth 리소스는 VaultAuthGlobal 리소스를 참조하고 그 JWT 인증 구성을 상속합니다.
  • 두 VaultAuth 리소스 모두 role이나 serviceAccount 필드가 없어요. role과 serviceAccount 필드가 VaultAuthGlobal 리소스에 정의되어 VaultAuth 리소스에 상속되기 때문입니다.

VaultAuthGlobal 일반 오류와 트러블슈팅

VaultAuthGlobal 리소스 문제를 추적할 수 있는 몇 가지 소스가 있어요.

  • Vault Secrets Operator 로그
  • 쿠버네티스 이벤트
  • 리소스 상태

각 소스의 오류 예시와 해결 방법은 다음과 같습니다.

Vault Secrets Operator 로그의 샘플 동기화 실패 출력:

{
  "level": "error",
  "ts": "2024-07-16T17:35:20Z",
  "logger": "cachingClientFactory",
  "msg": "Failed to get cacheKey from obj",
  "controller": "vaultstaticsecret",
  "controllerGroup": "secrets.hashicorp.com",
  "controllerKind": "VaultStaticSecret",
  "VaultStaticSecret": {
    "name": "app1",
    "namespace": "apps"
  },
  "namespace": "apps",
  "name": "app1",
  "reconcileID": "5201f597-6c5d-4d07-ae8f-30a39c80dc54",
  "error": "failed getting admin/default, err=VaultAuthGlobal.secrets.hashicorp.com \"default\" not found"
}

관련 쿠버네티스 이벤트를 확인해요.

$ kubectl events --types=Warning -n admin --for vaultauths.secrets.hashicorp.com/default -o json

VaultAuth 리소스에 대한 쿠버네티스 이벤트의 샘플 출력:

{
  "kind": "Event",
  "apiVersion": "v1",
  "metadata": {
    "name": "default.17e2c0da7b0e36b5",
    "namespace": "admin",
    "uid": "3ca6088e-7391-4b76-9443-a790ccae02c0",
    "resourceVersion": "634396",
    "creationTimestamp": "2024-07-16T17:14:12Z"
  },
  "involvedObject": {
    "kind": "VaultAuth",
    "namespace": "admin",
    "name": "default",
    "uid": "1dabe3a5-5479-4f5d-ac48-5db7eff7f822",
    "apiVersion": "secrets.hashicorp.com/v1beta1",
    "resourceVersion": "631994"
  },
  "reason": "Accepted",
  "message": "Failed to handle VaultAuth resource request: err=failed getting admin/default, err=VaultAuthGlobal.secrets.hashicorp.com \"default\" not found",
  "source": {
    "component": "VaultAuth"
  },
  "firstTimestamp": "2024-07-16T17:14:12Z",
  "lastTimestamp": "2024-07-16T17:15:53Z",
  "count": 25,
  "type": "Warning",
  "eventTime": null,
  "reportingComponent": "VaultAuth",
  "reportingInstance": ""
}

VaultAuth 리소스의 상태를 확인해요.

$ kubectl get vaultauths.secrets.hashicorp.com -n admin default -o jsonpath='{.status}'

VaultAuth의 상태 샘플 출력(가독성 있게 정리). VaultAuthGlobalRef 조건 이유에서 valid 필드가 false가 됩니다.

{
  "conditions": [
    {
      "lastTransitionTime": "2024-07-16T15:35:43Z",
      "message": "failed getting admin/default, err=VaultAuthGlobal.secrets.hashicorp.com \"default\" not found",
      "observedGeneration": 3,
      "reason": "VaultAuthGlobalRef",
      "status": "False",
      "type": "Available"
    }
  ],
  "specHash": "e264f241cb4ad776802924b6ad2aa272b11cffd570382605d1c2ddbdfd661ad3",
  "valid": false
}
  • 상황: VaultAuthGlobal 리소스를 찾지 못했거나 어떤 이유로 유효하지 않습니다. not found... 같은 오류 메시지로 표시됩니다. 해결: VaultAuthGlobal 구성 상속에 따라 참조하는 VaultAuth의 네임스페이스에 VaultAuthGlobal 리소스나 default VaultAuthGlobal 리소스가 존재하는지 확인하세요.
  • 상황: VaultAuth 리소스가 VaultAuthGlobal을 참조할 수 없습니다. target namespace "apps" is not allowed... 같은 오류 메시지로 표시됩니다. 해결: VaultAuthGlobal 리소스의 spec.allowedNamespaces 필드에 VaultAuth 리소스의 네임스페이스가 포함되어 있는지 확인하세요.
  • 상황: 필수 필드 누락으로 VaultAuth 리소스가 유효하지 않습니다. invalid merge: empty role 같은 오류 메시지로 표시됩니다. 해결: VaultAuth 리소스나 상속된 VaultAuthGlobal에 모든 필수 필드가 설정되어 있는지 확인하세요.

성공적으로 병합된 VaultAuth 리소스는 valid 필드가 true로 설정되고 조건이 다음과 같이 보입니다.

{
  "conditions": [
    {
      "lastTransitionTime": "2024-07-17T13:46:43Z",
      "message": "VaultAuthGlobal successfully merged, key=admin/default, uid=6aeb3559-8f42-48bf-b16a-2305bc9a9bed, generation=7",
      "observedGeneration": 1,
      "reason": "VaultAuthGlobalRef",
      "status": "True",
      "type": "Available"
    }
  ],
  "specHash": "5cbe5544d0557926e00002514871b95c49903a9d4496ef9b794c84f1e54db1a0",
  "valid": true
}

팁: message 필드의 키 값은 성공적으로 병합된 VaultAuthGlobal 객체의 namespace/name입니다. 이는 어떤 VaultAuthGlobal 객체가 VaultAuth 객체를 병합하는 데 사용됐는지 알고 싶을 때 유용해요.

일부 인증 엔진 자세히 보기

더 알아보기 (Learn more)