Vault로 SSO 구성하기

Vault로 SSO 구성하기 (Configure SSO with Vault)

제로 트러스트(Zero-trust) 아키텍처를 구현하려면 조직 내 서비스에 아이덴티티 기반 접근을 제공해야 해요. OpenID Connect (OIDC)는 클라이언트가 아이덴티티 공급자를 통해 자신의 정체성을 확인할 수 있게 해줘요. Vault 1.9.0은 authorization code 흐름으로 Vault를 OIDC 아이덴티티 공급자로 구성하는 기능을 도입했고, Nomad 1.5.0은 단일 로그온(SSO) 방식으로서 OIDC 지원을 도입했어요. Nomad 1.5.0부터 OIDC를 사용해 사용자를 인증하고 그 권한을 Nomad ACL 역할과 정책에 매핑할 수 있어요.

출처: 문서

본문

이 가이드에서는 Vault를 OIDC 공급자로, Nomad를 그 클라이언트로 설정할 거예요.

참고: 이 가이드에서 Nomad는 기밀(confidential) OIDC 클라이언트로 작동해요. 공용(public) OIDC 클라이언트를 구성하려면 OIDC 공급자 문서를 참조해요.

사전 요구 사항 (Prerequisites)

이 가이드에서 설명하는 작업을 수행하려면 다음이 필요해요:

참고: 이 기능은 Vault 1.9에서 Technical Preview 기능으로 처음 도입됐어요. Vault 1.10부터 일반 공개(GA)되었어요.

정책 요구 사항 (Policy requirements)

이 가이드의 목적을 위해 개발 모드로 실행되는 Vault를 작업할 때 root 토큰을 사용할 거예요.

비개발 Vault 환경에서 작업할 때는 토큰 정책에 다음 권한이 포함되어야 해요:

path "identity/*" {
  capabilities = [ "create", "read", "update", "delete", "list" ]
}

# To enable userpass auth method
path "sys/auth/userpass" {
  capabilities = [ "create", "read", "update", "delete" ]
}

# To create a new user, "end-user" for userpass
path "auth/userpass/users/*" {
   capabilities = [ "create", "read", "update", "delete", "list" ]
}

자세한 내용은 Vault 정책 튜토리얼을 참조해요.

Vault 시작 (Start Vault)

터미널에서 root를 루트 토큰으로 하는 Vault 개발 서버를 시작해요.

Vault 개발 서버는 기본적으로 127.0.0.1:8200에서 실행돼요. 서버는 이제 초기화되고 봉인이 해제(unsealed)되었어요.

경고

프로덕션에서 Vault 개발 서버를 실행하지 마세요. 이 방식은 인메모리 데이터베이스로 Vault 서버를 시작하며 테스트 목적으로만 사용해야 해요.

다른 터미널 세션을 열고 Vault 서버 주소에 대한 환경 변수를 내보내요.

Vault 토큰에 대한 환경 변수를 내보내요.

참고: 이러한 작업을 위해 Vault의 root 토큰을 사용할 수 있어요. 그러나 루트 토큰은 초기 설정이나 비상 상황에서만 사용할 것을 권장해요. 모범 사례로 정책 요구 사항을 충족하는 인증 방법이나 토큰을 사용해요.

Vault 서버가 준비됐어요.

  1. HCP Portal을 실행하고 로그인해요.
  2. 왼쪽 탐색 창에서 Vault를 클릭해요.
  3. Vault clusters 창에서 vault-cluster를 클릭해요.
  4. Cluster URLs 아래에서 Public Cluster URL을 클릭해요. 이렇게 하면 URL이 클립보드에 복사돼요.
  5. 터미널에서 VAULT_ADDR 환경 변수를 HCP에서 복사한 공용 클러스터 URL로 설정해요.
  1. Overview 페이지로 돌아가 Generate token을 클릭해요. 토큰을 생성하는 데 몇 시간이 걸릴 수 있어요.
  2. Copy를 클릭해 Admin Token을 복사해요.
  3. 터미널로 돌아가 VAULT_TOKEN 환경 변수를 HCP에서 복사한 토큰으로 설정해요.
  1. VAULT_NAMESPACE 환경 변수를 admin으로 설정해요.

admin 네임스페이스는 HCP Vault가 자동으로 만드는 최상위 네임스페이스예요. 기본적으로 모든 CLI 작업은 이 환경 변수에 정의된 네임스페이스를 사용해요.

  1. Vault 클러스터에 대한 연결을 확인해요.

Key                      Value
---                      -----
Recovery Seal Type       shamir
Initialized              true
Sealed                   false
Total Recovery Shares    1
Threshold                1
Version                  1.9.2+ent
Storage Type             raft
...snipped...

Vault Dedicated 서버가 준비됐어요.

Vault 인증 구성 (Configure Vault authentication)

Vault auth methods는 클라이언트를 인증하고 아이덴티티와 정책을 할당해요. Vault가 OIDC 공급자로 작동할 때 아이덴티티의 원천이며 이러한 auth methods가 그 아이덴티티를 검증해요.

  1. 기본 경로에서 userpass auth method를 활성화해요.
  1. 비밀번호가 password인 end-user라는 사용자를 만들어요.
    password="password" \
    token_ttl="1h"

이 사용자는 Vault로 인증되며 기본 접근 정책이 할당돼요.

더 알아보기: 자세한 내용은 Userpass Auth Method 문서를 참조해요.

Vault 아이덴티티 엔티티와 그룹 만들기 (Create Vault identity entity and group)

클라이언트는 Vault 서버에서 활성화된 다양한 아이덴티티 공급자와 여러 계정을 가질 수 있어요. Vault 클라이언트는 엔티티(entity)로 매핑될 수 있고, 인증 공급자의 해당 계정은 별칭(alias)으로 매핑될 수 있어요.

  1. end-user에 대한 세부 정보로 아이덴티티 엔티티를 만들어요.
    name="end-user" \
    disabled=false
  1. 엔티티에 할당된 ID를 저장하는 ENTITY_ID라는 환경 변수를 만들어요.
  1. engineering이라는 아이덴티티 그룹을 만들고 end-user를 멤버로 추가해요.
    name="engineering" \
    member_entity_ids="$ENTITY_ID"
  1. 그룹에 할당된 ID를 저장하는 GROUP_ID라는 환경 변수를 만들어요.

end-user 엔티티는 engineering 그룹의 멤버예요. 엔티티 별칭은 엔티티를 인증 방법의 클라이언트에 매핑해요. 이 매핑에는 엔티티 ID와 인증 accessor ID가 필요해요.

  1. userpass 인증 방법의 accessor 값을 저장하는 USERPASS_ACCESSOR라는 변수를 만들어요.
  1. end-user 엔티티를 end-user 사용자와 매핑하는 엔티티 별칭을 만들어요.
    name="end-user" \
    canonical_id="$ENTITY_ID" \
    mount_accessor="$USERPASS_ACCESSOR"

엔티티와 사용자는 서로 별칭이에요.

더 알아보기: 엔티티와 그룹 튜토리얼에서 아이덴티티에 대해 더 알아보세요.

Vault OIDC 클라이언트 만들기 (Create a Vault OIDC client)

Vault OIDC 클라이언트는 OIDC 할당(assignment)이라는 리소스, 암호화 키, 클라이언트 콜백 URL, 검증 시 TTL(time-to-live)을 함께 연결해요.

OIDC 할당은 이 클라이언트로 인증할 수 있는 Vault 엔티티와 그룹의 목록을 설명해요.

  1. end-user 엔티티와 engineering 그룹을 승인하는 my-assignment라는 할당을 만들어요.
    entity_ids="${ENTITY_ID}" \
    group_ids="${GROUP_ID}"

Vault OIDC 인증 과정은 인증 흐름에서 생성되는 JSON 웹 토큰(JWT)을 서명하고 검증할 암호화 키가 필요해요.

  1. my-key라는 키를 만들어요.
    allowed_client_ids="*" \
    verification_ttl="2h" \
    rotation_period="1h" \
    algorithm="RS256"

allowed_client_ids가 *로 설정되어 있으므로 이 키는 모든 Vault OIDC 클라이언트가 사용할 수 있어요.

  1. nomad라는 OIDC 클라이언트를 만들어요.
    redirect_uris="http://localhost:4649/oidc/callback,http://localhost:4200/ui/settings/tokens" \
    assignments="my-assignment" \
    key="my-key" \
    id_token_ttl="30m" \
    access_token_ttl="1h"

redirect_uris 플래그는 클라이언트의 콜백 URL을 설명하며, 값은 기본 포트에서 실행되는 Nomad 서비스의 주소예요. assignments 플래그는 my-assignment에 정의된 엔티티와 그룹에만 접근을 제한해요. id_token_ttl 플래그는 ID 토큰의 만료를 30분으로 설정해요. access_token_ttl 플래그는 액세스 토큰의 만료를 1시간으로 설정해요.

  1. nomad 클라이언트의 client_id 필드를 저장하는 CLIENT_ID라는 환경 변수를 만들어요.

Vault OIDC 공급자 만들기 (Create a Vault OIDC provider)

Vault OIDC 공급자는 하나 이상의 클라이언트와 Vault OIDC 스코프를 지원해요. 이러한 스코프는 템플릿으로 표현되는 메타데이터 클레임을 정의해요. 클레임은 사용자와 OIDC 서비스에 대한 정보를 포함하는 키-값 쌍이에요.

  1. 사용자 스코프 템플릿을 저장하는 USER_SCOPE_TEMPLATE라는 환경 변수를 만들어요.
  1. 사용자 스코프 템플릿으로 user라는 Vault OIDC 스코프를 정의해요.
    description="The user scope provides claims using Vault identity entity metadata" \
    template="$(echo ${USER_SCOPE_TEMPLATE} | base64)"
  1. 그룹 스코프 템플릿을 저장하는 GROUPS_SCOPE_TEMPLATE라는 환경 변수를 만들어요.

이 템플릿은 정의된 모든 그룹의 이름을 검색해요.

  1. 그룹 스코프 템플릿으로 groups라는 Vault OIDC 스코프를 정의해요.
    description="The groups scope provides the groups claim using Vault group membership" \
    template="$(echo ${GROUPS_SCOPE_TEMPLATE} | base64)"
  1. my-provider라는 Vault OIDC 공급자를 만들고 클라이언트 ID와 스코프 목록을 제공해요. 공급자는 nomad 클라이언트에 접근을 부여해요.
    allowed_client_ids="${CLIENT_ID}" \
    scopes_supported="groups"

Vault Dedicated는 issuer URL에 프라이빗 주소를 사용해요. 이 가이드에서는 공용 URL과 일치하도록 issuer 값을 재정의할 거예요.

    issuer="$(echo $VAULT_ADDR)" \
    allowed_client_ids="${CLIENT_ID}" \
    scopes_supported="groups"
  1. Vault OIDC 구성 엔드포인트를 표시해요.
    --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
    $VAULT_ADDR/v1/identity/oidc/provider/my-provider/.well-known/openid-configuration | jq
  1. Vault OIDC 공개 키를 표시해요.
    --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
    $VAULT_ADDR/v1/identity/oidc/provider/my-provider/.well-known/keys | jq

Nomad 시작 (Start Nomad)

Nomad 개발 에이전트는 서버와 클라이언트가 포함된 Nomad 인스턴스를 생성해요. 자세한 내용은 클러스터 시작 튜토리얼을 참조해요.

다른 터미널에서 ACL이 활성화된 개발 모드로 Nomad 에이전트를 시작해요.


==> No configuration files loaded
==> Starting Nomad agent...
==> Nomad agent configuration:

       Advertise Addrs: HTTP: 127.0.0.1:4646; RPC: 127.0.0.1:4647; Serf: 127.0.0.1:4648
            Bind Addrs: HTTP: [127.0.0.1:4646]; RPC: 127.0.0.1:4647; Serf: 127.0.0.1:4648
                Client: true
             Log Level: DEBUG
                Region: global (DC: dc1)
                Server: true
               Version: 1.5.0

...snip...

Nomad 서버가 준비됐어요.

Nomad OIDC 인증 구성 (Configure Nomad OIDC auth)

  1. my-provider라는 Vault OIDC 공급자의 issuer 필드를 저장하는 ISSUER라는 환경 변수를 만들어요.
    --header "X-Vault-Namespace: $VAULT_NAMESPACE" \
    $VAULT_ADDR/v1/identity/oidc/provider/my-provider/.well-known/openid-configuration | jq -r .issuer)
  1. nomad라는 Vault OIDC 클라이언트의 client_secret 필드를 저장하는 CLIENT_SECRET이라는 환경 변수를 만들어요.
  1. 부트스트랩 과정을 실행하고, 관리 토큰의 값을 저장해 NOMAD_TOKEN 환경 변수로 내보내요.
$ export NOMAD_TOKEN
  1. "default" 네임스페이스에 읽기 접근을 허용하는 Nomad 정책을 만들어요.

acl_policy_engineering_read.hcl라는 파일을 만들고 다음 내용을 추가한 후 저장해요.

  policy = "read"
}

node {
  policy = "read"
}

정책을 적용해요.

  1. 엔지니어에게 할당할 정책을 포함하는 해당 역할을 만들어요.
    -name=engineering-read \
    -policy=engineering-read
  1. OIDC auth method의 구성을 만들어요.

acl_auth_method.json이라는 파일을 만들고 다음 내용을 추가한 후 $ISSUER, $CLIENT_ID, $CLIENT_SECRET를 각각의 환경 변수에 저장된 값으로 대체하고 저장해요.

  "OIDCDiscoveryURL": $ISSUER,
  "OIDCClientID": $CLIENT_ID,
  "OIDCClientSecret": $CLIENT_SECRET,
  "BoundAudiences": [$CLIENT_ID],
  "OIDCScopes": ["groups"],
  "AllowedRedirectURIs": [
    "http://localhost:4649/oidc/callback",
    "http://localhost:4646/ui/settings/tokens"
  ],
  "ListClaimMappings": {
    "groups": "roles"
  }
}

ListClaimMappings 필드는 OIDC 공급자의 어떤 클레임을 Nomad의 어떤 ACL 개념에 매핑할지 지정해요. 앞서 만든 Vault "group"은 Nomad의 "role"에 매핑돼요.

  1. 새 OIDC 인증 방법을 만들고 Vault OIDC 공급자를 사용하도록 구성해요.
    -default=true \
    -name=vault \
    -token-locality=global \
    -max-token-ttl="10m" \
    -type=oidc \
    -config @acl_auth_method.json
  1. OIDC 클레임을 Nomad 정책과 역할로 평가하는 바인딩 규칙을 만들어요.
    -auth-method=vault \
    -bind-type=role \
    -bind-name="engineering-read" \
    -selector="engineering in list.roles"

Nomad OIDC 인증이 구성됐고 end-user가 인증할 준비가 됐어요.

Nomad로 인증 (Authenticate with Nomad)

Nomad에 인증해요. vault가 기본 방법으로 구성됐으므로 -method 플래그는 선택 사항이에요.

브라우저에서 Vault 로그인 화면이 열려요. Method 드롭다운에서 Username을 선택하고 자격 증명으로 end-user와 password를 입력해요.

nomad login 명령은 인증이 성공했음을 확인하고 생성된 Nomad ACL 토큰을 표시해요.


Accessor ID  = 48008488-21ae-35d7-f1d6-0066a7eb902a
Secret ID    = d7a803e6-abd6-a80e-dd95-5f88d904cc9e
Name         = vault
Type         = client
Global       = true
Create Time  = 2023-01-13 10:06:35.933899 +0000 UTC
Expiry Time  = 2023-01-13 10:16:35.933899 +0000 UTC
Create Index = 19
Modify Index = 19
Policies     = []

Roles
ID                                    Name
197deab1-a963-91fc-2936-05923eecf0c0  engineering-read

다음 단계 (Next steps)

이 가이드에서는 Vault를 OIDC 공급자로, Nomad를 클라이언트로 구성했어요. Vault를 OIDC 공급자로 구성하는 방법에 대해 더 알아보세요.

더 알아보기 (Learn more)