SVID 발행, 검증, 사용하기

SVID 발행, 검증, 사용하기

적절한 Vault Enterprise 라이선스가 필요해요.

Vault가 발행한 JWT-SVID를 사용해 SPIFFE를 지원하는 서비스와 인증할 수 있어요.

SPIFFE에 익숙하지 않다면 SPIFFE 개요를 참고해 Vault에서 SPIFFE 시크릿 엔진이 어떻게 작동하는지 알아보세요.

Vault SPIFFE 시크릿 엔진의 작동 예시를 위해 이 문서를 그대로 따라 하세요. 프로덕션 호스트에서 이 단계를 수행하면 그 구성이 바뀔 거예요. 일반 구성 지침은 설정 가이드를 참고하세요.

이 문서에서 사용하는 Vault와 신뢰 당사자는 단순함을 위해 둘 다 로컬 컨테이너로 실행돼요.

출처: 문서

본문

요구 사항 (Requirements)

  • 활성 Vault Enterprise 라이선스.
  • Docker 또는 Docker Desktop 설치.
  • curl, jq, awk, cut, tr, base64를 포함한 셸에서 사용 가능한 일반 명령줄 도구.

Vault 설정하기 (Set up Vault)

이 섹션은 워크로드가 Vault에서 발행한 JWT-SVID로 인증되도록 하는 데 필요한 최소 구성을 안내해요. SPIFFE 프로덕션이나 하드닝 가이드는 아니에요.

1. Vault Enterprise 라이선스를 환경 변수로 내보냅니다.

$ export VAULT_LICENSE=C10WMSH0W...snip...S3ASM3STR33T

2. Vault를 시작합니다.

$ docker run -d --name vault -p 8200:8200 \
    -e VAULT_DEV_ROOT_TOKEN_ID=root \
    -e VAULT_LICENSE=$VAULT_LICENSE \
    hashicorp/vault-enterprise:latest \
    server -dev

루트 토큰: dev 모드 서버는 초기 루트 토큰 값이 설정된 상태로 시작해요. 루트 토큰은 Vault 서버에 대한 전체 접근을 제공하므로 프로덕션 환경에서는 매우 신중하게 사용해야 해요. 편의를 위해 dev 모드에서 Vault를 시작하는 루트 토큰 값을 제공할 수 있으며, 이렇게 하면 이 튜토리얼의 학습 목표에 단계를 집중할 수 있어요.

3. Vault에 접근할 환경 변수를 내보냅니다.

$ export VAULT_ADDR="http://127.0.0.1:8200" VAULT_TOKEN="root"

4. 엔진을 활성화합니다.

$ vault secrets enable spiffe
Success! Enabled the spiffe secrets engine at: spiffe/

5. 신뢰 도메인을 구성합니다.

$ vault write spiffe/config trust_domain=example.org

6. 역할을 만듭니다.

$ vault write spiffe/role/workload \
    template='{"sub": "/payments-api"}' \
    ttl=1h

sub는 경로를 나타내요. Vault가 JWT-SVID를 발행할 때 구성된 신뢰 도메인을 접두사로 붙여 값을 spiffe://example.org/payments-api로 확장해요.

7. JWT-SVID를 발행합니다.

$ JWT_SVID=$(vault write -format=json \
    spiffe/role/workload/mintjwt \
    audience=example-relying-party | jq -r '.data.token') \
    && echo $JWT_SVID

8. JWT 클레임을 검토합니다.

$ echo "$JWT_SVID" | cut -d. -f2 | tr '_-' '/+' | \
   awk '{ while (length($0) % 4) $0 = $0 "="; print }' | \
   base64 -d 2>/dev/null | jq .

SVID는 subspiffe://example.org/payments-api로 설정된 것 외에 iss, aud, iat, exp, vault.entity.id를 포함해요.

예시 출력:

{
  "aud": [
    "example-relying-party"
  ],
  "exp": 1786629520,
  "iat": 1786629220,
  "iss": "http://0.0.0.0:8200/v1/spiffe",
  "nbf": 1786629220,
  "sub": "spiffe://example.org/payments-api",
  "vault": {
    "entity": {
      "id": ""
    }
  }
}

9. 시크릿 엔진 OIDC 구성을 검토합니다.

$ curl -s $VAULT_ADDR/v1/spiffe/.well-known/openid-configuration | jq .

예시 출력:

{
  "issuer": "http://0.0.0.0:8200/v1/spiffe",
  "jwks_uri": "http://0.0.0.0:8200/v1/spiffe/.well-known/keys",
  "response_types_supported": [
    "id_token"
  ],
  "subject_types_supported": [
    "public"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256",
    "RS384",
    "RS512",
    "ES256",
    "ES384",
    "ES512"
  ]
}

OIDC 디스커버리 문서는 발급자 URL, 키를 찾을 위치(jwks_uri), 지원되는 서명 알고리즘 같은 발급자에 대한 메타데이터를 포함해요. OIDC 인식 클라이언트는 먼저 디스커버리 문서를 가져와 이 발급자의 토큰을 검증하는 방법을 결정해요.

10. 시크릿 엔진이 게시한 키를 검토합니다.

$ curl -s $VAULT_ADDR/v1/spiffe/.well-known/keys | jq .

예시 키 출력:

{
  "keys": [
    {
      "use": "sig",
      "kty": "RSA",
      "kid": "04b6c36a-b0f9-b2da-5b42-2f96d324c858",
      "alg": "RS256",
      "n": "t6bhERg7sgITXoOsOATC94Pjw3_d1NCuQ3xQms0qwSMqk1boWRkteQ8CJdI5upY_n9CMQP7LjwKpmv04SHxL9qtxZr5ur9kx78ww0AUy8CWambFjPBf3H7xHS1oPrbXL_ZzeklwxJVI9OQdgRT7ysvifWItqPNiGH6skUqQcjLf0wo3cNCypixAmsU7liKqFtBsd-dlhgwlG7EGeYOQMhWJRF13ifAsml073mPG3s4lMqjUwIbajh3guB1dIoN7tUx7xrEZwlEn2ouNjxbTzrW_tvGrO9WrJqW0JtFibrA2GmT26XC5v4GOsAF-PVYu4AD07crHG_2rkFNo8vDeopQ",
      "e": "AQAB"
    },
    {
      "use": "sig",
      "kty": "RSA",
      "kid": "caeae134-948b-4364-8caa-ca951d572ffa",
      "alg": "RS256",
      "n": "zitKBBClfnXbTQS3eUYrhm2rz6QO5Sg0ybp5XqLYwVIw7lMPJk8D3tLa98AlCncvMo-g6lVRI57qYxJKKAASv5UpEm3PRKMqVdlIeXLSSRnPWteuaZ4wogHxy437RD17Mp8jCPGIfu20r6gZ2vNvd0LVqLJrntttq5ewFsTTvzoKbRizcy5WIT3O_rJfJVxap3Pk3SL0t8kLed2DN-l2ZMtvce4edWcq6LSIL8UgkM9AWl6DAr_IMBMiHRnqGVrek7E1UZmcuehThjy0ySewDBZLVu6OZ9iOineXSstpWA6kqF3Kr0-Sp_Po1jqZj5cOarDFC-yNSNUYuMSgu_K4Aw",
      "e": "AQAB"
    }
  ]
}

이것들은 JWT-SVID 서명을 검증하는 데 사용되는 공개 키예요.

OIDC 호환 JWT 라이브러리는 OIDC 구성에서 관련 메타데이터를 읽고, .well-known/keys의 JWKS를 읽어 JWT를 검증해요.

JWT-SVID로 로그인하기

Vault 이외의 다른 것이 JWT-SVID를 수락하는지 보려면, 엔진의 JWKS 엔드포인트를 가리키는 내장 JWT 인증으로 Grafana를 실행하세요. Grafana의 JWT 인증에는 JWKS URL만 필요해요.

참고: 이 예시 구성은 프로덕션 배포에 적합하지 않아요.

1. Vault의 JWKS 키를 파일로 씁니다.

$ curl -s $VAULT_ADDR/v1/spiffe/.well-known/keys | tee jwks.json | jq .

Grafana는 jwk_set_url에 HTTPS를 요구해요. 이 단계는 파일을 직접 제공해 Grafana를 시작할 수 있게 해 줘요. 프로덕션 환경에서는 Vault에 직접 TLS 연결로 이 작업을 수행할 거예요.

2. Grafana를 시작합니다.

$ docker run -d --name grafana -p 3000:3000 \
    -v "$(pwd)/jwks.json:/etc/grafana/jwks.json:ro" \
    -e "GF_AUTH_JWT_ENABLED=true" \
    -e "GF_AUTH_JWT_HEADER_NAME=X-JWT-Assertion" \
    -e "GF_AUTH_JWT_JWK_SET_FILE=/etc/grafana/jwks.json" \
    -e "GF_AUTH_JWT_USERNAME_CLAIM=sub" \
    -e "GF_AUTH_JWT_AUTO_SIGN_UP=true" \
    grafana/grafana-oss:latest

3. Vault가 발행한 SVID로 Grafana에 로그인합니다.

$ curl -H "X-JWT-Assertion: $JWT_SVID" http://localhost:3000/api/user | jq

Grafana는 JWT-SVID를 유효한 크레덴셜로 수락해요. 성공적인 응답은 로그인된 사용자를 반환하며, loginsub 클레임의 SPIFFE ID로 설정돼요.

예시 출력:

{
  "id": 2,
  "uid": "ffv2e0k8lrpq8e",
  "email": "spiffe://example.org/payments-api",
  "name": "",
  "login": "spiffe://example.org/payments-api",
  "theme": "",
  "orgId": 1,
  "isGrafanaAdmin": false,
  "isDisabled": false,
  "isExternal": true,
  "isExternallySynced": true,
  "isGrafanaAdminExternallySynced": false,
  "authLabels": [
    "JWT"
  ],
  "updatedAt": "2026-08-13T14:28:22Z",
  "createdAt": "2026-08-13T14:28:22Z",
  "avatarUrl": "/avatar/c63487a5cd574fa9137173ec4d919b56",
  "isProvisioned": false
}

출력은 Grafana가 JWT-SVID의 sub 클레임을 emaillogin 필드에 매핑하는 것을 보여 줘요. Grafana는 JWKS에 대해 서명을 검증한 다음 user_claim=sub를 적용해 X-JWT-Assertion 헤더로 전달한 JWT_SVID 토큰에서 신원을 가져와요.

다음 단계 (Next steps)

더 알아보기 (Learn more)

  • SPIFFE 표준에 대한 자세한 내용은 spiffe.io에서 확인하세요.
  • Vault SPIFFE 시크릿 엔진 전체 API는 SPIFFE API 문서를 참고하세요.