Vault ACL 통합

Vault ACL 통합 (Integrate Vault ACL)

Vault ACL 시스템은 클러스터를 무단 접근으로부터 보호해요. Vault와 Nomad 통합이 작동하려면 제대로 구성되어야 해요.

출처: 문서

본문

Nomad 워크로드 아이덴티티 (Nomad workload identities)

Nomad 1.10.0부터 Nomad 클라이언트는 작업의 워크로드 아이덴티티(Workload Identity)를 사용해 Vault에 인증하고 작업별 Vault ACL 토큰을 얻어요.

기본적으로 Nomad는 template 블록에서 Variables를 읽는 것처럼 Nomad 자체에 접근하는 데 사용할 수 있는 작업에 대해서만 워크로드 아이덴티티를 생성해요. Vault에 접근하려면 작업에 identity 블록으로 정의된 추가 워크로드 아이덴티티가 있어야 해요.

이러한 추가 아이덴티티를 모든 작업에 추가하지 않아도 되도록 Nomad 서버를 vault.default_identity 에이전트 구성으로 설정할 수 있어요. 작업이 등록되면 Nomad 서버는 vault 블록이 있는 작업을 이 기본 아이덴티티로 업데이트해요.

작업에서 Vault용 아이덴티티를 직접 지정할 수도 있어요. 지정하면 Nomad 서버 구성을 덮어써요. 자세한 내용은 identity 블록 문서의 Vault용 워크로드 아이덴티티 섹션을 참조해요.

Vault 인증 구성 (Configuring Vault authentication)

Vault는 이러한 Nomad 워크로드 아이덴티티를 수신·검증·신뢰하도록 구성되어야 해요. 워크로드 아이덴티티가 JSON Web Tokens (JWT)로 인코딩되므로 JWT ACL auth method를 만들어야 해요. auth method는 Nomad가 워크로드 아이덴티티를 Vault ACL 토큰으로 교환하는 데 사용할 수 있는 엔드포인트예요.

자세한 내용은 Vault의 인증(Authentication) 문서를 참조해요.

Vault auth method (Vault auth method)

auth method 구성은 Nomad의 JSON Web Key Set (JWKS) URL을 가리켜요. Vault 서버가 이 URL을 호출해 Nomad가 워크로드 아이덴티티 서명에 사용하는 공개 키를 검색해요. 이 키를 통해 Vault는 워크로드 아이덴티티의 출처를 검증하고 실제로 Nomad가 만들었다는 것을 확인할 수 있어요.

auth-method.json

  "jwks_url": "https://nomad.example.com:4646/.well-known/jwks.json",
  "jwt_supported_algs": ["RS256", "EdDSA"],
  "default_role": "nomad-workloads"
}

jwks_url 주소는 모든 Vault 서버가 도달할 수 있어야 하며, 단일 실패 지점을 피하기 위해 여러 Nomad 에이전트로 해석되어야 해요. Nomad 서버와 클라이언트 모두 이 요청을 처리할 수 있어요.

jwks_url 값 구성 방법에 대한 추가 정보는 JWKS URL에 대한 중요 고려 사항 섹션을 참조해요.

Vault에 접근해야 하는 할당(allocation)이 시작되면, 이를 실행하는 Nomad 클라이언트가 작업에 대한 Nomad 워크로드 아이덴티티를 Vault ACL 토큰으로 교환해요.

Vault ACL 역할 (Vault ACL role)

Vault ACL 역할은 여러 ACL 정책을 그룹화해 토큰에 적용하고 그것이 받는 권한을 결정해요.

auth method는 생성하는 ACL 토큰에 적용되는 기본 ACL 역할을 정의할 수 있어요. 기본 역할이 설정되지 않으면 작업에서 vault.role 파라미터나 Nomad 클라이언트 구성의 vault.create_from_role을 사용해 역할을 제공해야 해요.

auth-method.json

  "jwks_url": "https://nomad.example.com:4646/.well-known/jwks.json",
  "jwt_supported_algs": ["RS256", "EdDSA"],
  "default_role": "nomad-workloads"
}

ACL 역할은 bound_audiences를 사용해 허용된 audience 값 목록을 지정해요. 이 값은 Nomad 워크로드 아이덴티티 aud 파라미터에 정의된 값과 최소 하나는 일치해야 해요. 보안상의 이유로 단일 audience 값만 정의하는 것을 권장해요.

acl-role.json

  "role_type": "jwt",
  "bound_audiences": ["vault.io"],
  "bound_claims": {
     "nomad_namespace": "default",
     "nomad_job_id": "mongo"
  },
  "user_claim": "/nomad_job_id",
  "user_claim_json_pointer": true,
  "claim_mappings": {
    "nomad_namespace": "nomad_namespace",
    "nomad_job_id": "nomad_job_id",
    "nomad_task": "nomad_task"
  },
  "token_type": "service",
  "token_policies": ["nomad-workloads"],
  "token_period": "30m",
  "token_explicit_max_ttl": 0
}

Nomad 워크로드 아이덴티티는 Vault ACL 구성에서 참조할 수 있는 클레임(claims) 집합을 가져요. ACL 역할은 claim_mappings 파라미터를 사용해 이러한 클레임 중 어떤 것이 나머지 구성에서 사용 가능해지는지 결정해요.

bound_claims 파라미터는 클레임에 따라 역할을 사용할 수 있는 워크로드 아이덴티티를 제한해요. 자세한 내용은 Vault의 Bound Claims 문서를 참조해요.

acl-role.json

  "role_type": "jwt",
  "bound_audiences": ["vault.io"],
  "bound_claims": {
     "nomad_namespace": "default",
     "nomad_job_id": "mongo"
  },
  "user_claim": "/nomad_job_id",
  "user_claim_json_pointer": true,
  "claim_mappings": {
    "nomad_namespace": "nomad_namespace",
    "nomad_job_id": "nomad_job_id",
    "nomad_task": "nomad_task"
  },
  "token_type": "service",
  "token_policies": ["nomad-workloads"],
  "token_period": "30m",
  "token_explicit_max_ttl": 0
}

Vault에는 다양한 유형의 ACL 토큰이 있어요. Nomad는 일반적으로 service 유형의 토큰을 사용해요. 워크로드가 활성 상태인 동안 갱신할 수 있기 때문이에요. Nomad는 생성한 Vault ACL 토큰을 만료 전에 자동으로 갱신해요. 토큰이 필요한 만큼 갱신 가능하도록 token_explicit_max_ttl은 0으로 설정해야 해요.

대안으로 batch 토큰을 사용할 수도 있어요. 이는 작업 시작 시점이나 짧은 수명의 prestart 작업에서 시크릿을 한 번만 요청할 때만 사용해야 해요. 장기 실행 작업은 template 블록을 통해 Vault 시크릿을 얻는다면 절대 allow_token_expiration=true로 설정하지 마세요. Vault 토큰이 만료되면 template 러너가 [vault_retry][] 시도가 소진될 때까지 Vault에 실패하는 요청을 계속 보내고, 그 시점에 작업이 실패하기 때문이에요. Vault의 batch 토큰은 갱신할 수 없으며, Nomad는 워크로드 아이덴티티를 사용하도록 구성되면 갱신을 시도하지 않아요.

acl-role.json

  "role_type": "jwt",
  "bound_audiences": ["vault.io"],
  "bound_claims": {
     "nomad_namespace": "default",
     "nomad_job_id": "mongo"
  },
  "user_claim": "/nomad_job_id",
  "user_claim_json_pointer": true,
  "claim_mappings": {
    "nomad_namespace": "nomad_namespace",
    "nomad_job_id": "nomad_job_id",
    "nomad_task": "nomad_task"
  },
  "token_policies": ["nomad-workloads"],
  "token_type": "service",
  "token_period": "30m",
  "token_explicit_max_ttl": 0
}
Vault ACL 정책 (Vault ACL policy)

Vault ACL 역할에는 하나 이상의 ACL 정책이 연결될 수 있어요. Vault ACL 정책은 ACL 토큰에 부여된 권한을 정의해요.

acl-role.json

  "role_type": "jwt",
  "bound_audiences": ["vault.io"],
  "bound_claims": {
     "nomad_namespace": "default",
     "nomad_job_id": "mongo"
  },
  "user_claim": "/nomad_job_id",
  "user_claim_json_pointer": true,
  "claim_mappings": {
    "nomad_namespace": "nomad_namespace",
    "nomad_job_id": "nomad_job_id",
    "nomad_task": "nomad_task"
  },
  "token_policies": ["nomad-workloads"],
  "token_type": "service",
  "token_period": "30m",
  "token_explicit_max_ttl": 0
}

ACL 정책은 템플릿 정책(templated policies)에서 ACL 역할이 노출한 Nomad 워크로드 아이덴티티 클레임의 동적 값을 참조할 수 있어요. 정확한 ACL 정책 규칙은 작업에 필요한 접근 수준에 따라 달라요.

다음 예시 ACL 정책은 secret/data/<job namespace>/<job name>/* 경로의 시크릿에 read 권한을 자동으로 부여해요. 여기서 <job namespace>와 <job name>은 워크로드 아이덴티티 클레임 nomad_namespace와 nomad_job_id에서 읽어요.

acl-policy.hcl

  capabilities = ["read"]
}

path "secret/data/{{identity.entity.aliases.auth_jwt_d34481ad.metadata.nomad_namespace}}/{{identity.entity.aliases.auth_jwt_d34481ad.metadata.nomad_job_id}}" {
  capabilities = ["read"]
}

path "secret/metadata/{{identity.entity.aliases.auth_jwt_d34481ad.metadata.nomad_namespace}}/*" {
  capabilities = ["list"]
}

path "secret/metadata/*" {
  capabilities = ["list"]
}

전체 구성 구조는 다음 다이어그램에 나와 있어요.

Vault 네임스페이스 (Vault namespaces) Enterprise

Vault Enterprise는 여러 네임스페이스를 지원하며, Nomad Enterprise의 작업은 vault.namespace 파라미터로 사용할 네임스페이스를 지정할 수 있어요. 다중 네임스페이스 환경에서는 설명한 인증 설정이 작업이 사용하는 각 Vault 네임스페이스에 적용되어야 해요.

JWKS URL에 대한 중요 고려 사항 (Important considerations about the JWKS URL)

권장 구성은 Vault 서버가 Nomad 에이전트(클라이언트 또는 서버)에 연결해 JSON Web Key Set 정보를 검색할 수 있다고 가정해요.

이 섹션은 Vault와 Nomad 클러스터가 어떻게 구성되고 배포되는지에 따라 고려해야 할 추가 측면을 다뤄요.

Nomad의 상호 TLS (Mutual TLS in Nomad)

Nomad의 프로덕션 배포에서는 상호 TLS를 사용하는 것을 적극 권장해요. mTLS가 활성화되면 Vault auth method에 클라이언트 인증서를 제공할 수 없으므로 tls.verify_https_client 구성을 false로 설정해야 해요. Nomad의 CA 인증서는 Vault auth method의 jwks_ca_pem 파라미터에 지정해야 해요.

대안으로 Nomad와의 상호 TLS 연결을 처리하고 표준 TLS로 JWKS URL 엔드포인트를 노출하는 프록시나 로드 밸런서에서 Nomad의 JWKS URL을 노출할 수도 있어요.

Vault 서버가 Nomad에 연결할 수 없는 경우 (Vault servers not able to connect to Nomad)

Vault 서버가 Nomad의 JWKS URL에 도달할 수 없다면, Nomad의 /.well-known/jwks.json 엔드포인트에서 공개 키를 읽어 jwt_validation_pubkeys 파라미터로 auth method에 직접 제공할 수 있어요. 키는 JWKS에서 PEM 형식으로 변환해야 해요.

Vault 서버가 도달할 수 있는 외부 위치에서 Nomad의 JWKS JSON 응답을 호스팅하고 그 주소를 jwks_url 값으로 사용할 수도 있어요.

Nomad 키가 주기적으로 회전(rotated) 된다는 점을 기억하는 것이 중요해요. 따라서 두 접근 방식 모두 자동화되어 계속 수행되어야 해요. 회전 빈도는 Nomad 서버의 server.root_key_rotation_threshold 구성으로 제어돼요. 키는 회전 임계값의 절반 시점에 미리 게시(prepublished)돼요.

추가 참고 자료 (Additional references)

Vault ACL과 Nomad 워크로드 아이덴티티 튜토리얼은 워크로드 아이덴티티용 Vault와 Nomad 구성을 위한 단계별 지침을 제공해요.

nomad setup vault 명령과 hashicorp-modules/nomad-setup/vault Terraform 모듈은 Vault 클러스터에 구성을 적용하는 과정을 자동화하는 데 도움이 돼요.

더 알아보기 (Learn more)