Cloud Foundry

Cloud Foundry (CF) 인증 방식

참고: 이 엔진은 TLS 또는 서명 검증의 일부로 외부 X.509 인증서를 사용할 수 있어요. SHA-1을 사용하는 X.509 인증서에 대한 서명 검증은 사용되지 않으며 Vault 1.12부터 해결 방법 없이는 더 이상 사용할 수 없어요. 자세한 내용은 deprecation 공지를 참고하세요.

cf 인증 방식은 CF 인스턴스에 대한 Vault 토큰을 검색하는 자동화 메커니즘을 제공해요. CF의 App and Container Identity Assurance를 활용해요. 높은 수준에서 이렇게 작동해요:

  1. CF_INSTANCE_KEY로 서명된 CF_INSTANCE_CERT를 포함한 요청을 Vault에 구성해요.
  2. Vault는 서명이 300초 이하로 오래되었거나 60초 미래인지 검증해요.
  3. Vault는 인증서가 미리 구성한 CA 인증서가 발급했는지 검증해요.
  4. Vault는 요청이 CF_INSTANCE_CERT의 개인 키로 서명되었는지 검증해요.
  5. Vault는 CF_INSTANCE_CERT의 애플리케이션 ID, 공간 ID, 조직 ID가 현재 존재하는지 검증해요.
  6. 모든 검사가 통과하면 Vault는 적절히 범위가 지정된 토큰을 발급해요.

출처: 문서

본문

알려진 위험 (Known risks)

이 인증 엔진은 CF의 인스턴스 신원 서비스를 사용해 사용자를 Vault에 인증해요. CF가 CA 인증서와 개인 키를 특정 사용자에게 언제든 사용할 수 있게 하므로, 그들에 접근하는 사람이 Vault 역할의 기준을 충족하는 신원 인증서를 자체 발급해 Vault에 의도하지 않은 접근을 얻을 수 있어요.

이런 이유로 이 인증 방식을 활성화한다면 인스턴스 신원 CA 인증서의 개인 키에 대한 접근을 신중하게 보호할 것을 권장해요. CredHub에서는 $ credhub get -n /cf/diego-instance-identity-root-ca 호출로 얻을 수 있어요.

CredHub ACL 시스템을 사용하든 CredHub에 접근할 수 있는 사용자를 신중히 제한하든, CredHub의 그 경로에 대한 접근을 제한하는 추가 단계를 취하세요.

사용법 (Usage)

플러그인 구성 준비하기

이 플러그인을 구성하려면 CF가 각 CF_INSTANCE_CERT를 발급하는 데 사용하는 CA 인증서를 모아야 하고, CF API에 접근하도록 구성해야 해요.

인스턴스 신원 CA 인증서를 얻으려면 cf dev 환경에서 다음으로 찾을 수 있어요:

$ bosh int --path /diego_instance_identity_ca ~/.cfdev/state/bosh/creds.yml

Ops Manager를 포함한 환경에서는 CredHub에서 찾을 수 있어요. CredHub에 접근하려면 먼저 PCF 명령줄 유틸리티를 설치하고 그것이 설명하는 metadata 파일을 사용해 인증하세요. 이 지침은 응답의 필요한 부분을 쉽게 파기 위해 jq도 사용해요.

그 단계들이 완료되면 CredHub에 사용할 크레덴셜을 얻으세요.

$ pcf settings | jq '.products[0].director_credhub_client_credentials'

Ops Manager VM에 SSH하세요.

$ ssh -i ops_mgr.pem ubuntu@$OPS_MGR_URL

위 OPS_MGR_URL은 https://를 앞에 붙이지 않아야 한다는 점을 기억하세요.

앞서 얻은 크레덴셜로 CredHub에 로그인하세요.

$ credhub login --client-name=director_to_credhub --client-secret=some-secret

CF가 인스턴스 신원 인증서를 발급하는 데 사용하는 루트 인증서를 봅니다.

$ credhub get -n /cf/diego-instance-identity-root-ca

그 호출의 출력은 두 인증서와 하나의 RSA 키를 포함해요. ca: | 아래의 인증서를 복사해 로컬 머신의 올바르게 형식화된 파일에 넣어야 해요. 다음은 올바르게 형식화된 CA 인증서의 예시예요.

$ cat ca.crt
-----BEGIN CERTIFICATE-----
MIIDNDCCAhygAwIBAgITPqTy1qvfHNEVuxsl9l1glY85OTANBgkqhkiG9w0BAQsF
ADAqMSgwJgYDVQQDEx9EaWVnbyBJbnN0YW5jZSBJZGVudGl0eSBSb290IENBMB4X
DTE5MDYwNjA5MTIwMVoXDTIyMDYwNTA5MTIwMVowKjEoMCYGA1UEAxMfRGllZ28g
SW5zdGFuY2UgSWRlbnRpdHkgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBALa8xGDYT/q3UzEKAsLDajhuHxPpIPFlCXwp6u8U5Qrf427Xof7n
rXRKzRu3g7E20U/OwzgBi3VZs8T29JGNWeA2k0HtX8oQ+Wc8Qngz9M8t1h9SZlx5
fGfxPt3x7xozaIGJ8p4HKQH1ZlirL7dzun7Y+7m6Ey8cMVsepqUs64r8+KpCbxKJ
rV04qtTNlr0LG3yOxSHlip+DDvUVL3jSFz/JDWxwCymiFBAh0QjG1LKp2FisURoX
GY+HJbf2StpK3i4dYnxQXQlMDpipozK7WFxv3gH4Q6YMZvlmIPidAF8FxfDIsYcq
TgQ5q0pr9mbu8oKbZ74vyZMqiy+r9vLhbu0CAwEAAaNTMFEwHQYDVR0OBBYEFAHf
pwqBhZ8/A6ZAvU+p5JPz/omjMB8GA1UdIwQYMBaAFAHfpwqBhZ8/A6ZAvU+p5JPz
/omjMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADuDJev+6bOC
v7t9SS4Nd/zeREuF9IKsHDHrYUZBIO1aBQbOO1iDtL4VA3LBEx6fOgN5fbxroUsz
X9/6PtxLe+5U8i5MOztK+OxxPrtDfnblXVb6IW4EKhTnWesS7R2WnOWtzqRQXKFU
voBn3QckLV1o9eqzYIE/aob4z0GaVanA9PSzzbVPsX79RCD1B7NmV0cKEQ7IrCrh
L7ElDV/GlNrtVdHjY0mwz9iu+0YJvxvcHDTERi106b28KXzJz+P5/hyg2wqRXzdI
faXAjW0kuq5nxyJUALwxD/8pz77uNt4w6WfJoSDM6XrAIhh15K3tZg9EzBmAZ/5D
jK0RcmCyaXw=
-----END CERTIFICATE-----

CA 인증서가 올바르게 형식화되었는지 확인하는 쉬운 방법은 OpenSSL을 이렇게 사용하는 것이에요.

$ openssl x509 -in ca.crt -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            3e:a4:f2:d6:ab:df:1c:d1:15:bb:1b:25:f6:5d:60:95:8f:39:39
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=Diego Instance Identity Root CA
        Validity
            Not Before: Jun  6 09:12:01 2019 GMT
            Not After : Jun  5 09:12:01 2022 GMT
        Subject: CN=Diego Instance Identity Root CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:b6:bc:c4:60:d8:4f:fa:b7:53:31:0a:02:c2:c3:
                    6a:38:6e:1f:13:e9:20:f1:65:09:7c:29:ea:ef:14:
                    e5:0a:df:e3:6e:d7:a1:fe:e7:ad:74:4a:cd:1b:b7:
                    83:b1:36:d1:4f:ce:c3:38:01:8b:75:59:b3:c4:f6:
                    f4:91:8d:59:e0:36:93:41:ed:5f:ca:10:f9:67:3c:
                    42:78:33:f4:cf:2d:d6:1f:52:66:5c:79:7c:67:f1:
                    3e:dd:f1:ef:1a:33:68:81:89:f2:9e:07:29:01:f5:
                    66:58:ab:2f:b7:73:ba:7e:d8:fb:b9:ba:13:2f:1c:
                    31:5b:1e:a6:a5:2c:eb:8a:fc:f8:aa:42:6f:12:89:
                    ad:5d:38:aa:d4:cd:96:bd:0b:1b:7c:8e:c5:21:e5:
                    8a:9f:83:0e:f5:15:2f:78:d2:17:3f:c9:0d:6c:70:
                    0b:29:a2:14:10:21:d1:08:c6:d4:b2:a9:d8:58:ac:
                    51:1a:17:19:8f:87:25:b7:f6:4a:da:4a:de:2e:1d:
                    62:7c:50:5d:09:4c:0e:98:a9:a3:32:bb:58:5c:6f:
                    de:01:f8:43:a6:0c:66:f9:66:20:f8:9d:00:5f:05:
                    c5:f0:c8:b1:87:2a:4e:04:39:ab:4a:6b:f6:66:ee:
                    f2:82:9b:67:be:2f:c9:93:2a:8b:2f:ab:f6:f2:e1:
                    6e:ed
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                01:DF:A7:0A:81:85:9F:3F:03:A6:40:BD:4F:A9:E4:93:F3:FE:89:A3
            X509v3 Authority Key Identifier:
                keyid:01:DF:A7:0A:81:85:9F:3F:03:A6:40:BD:4F:A9:E4:93:F3:FE:89:A3

            X509v3 Basic Constraints: critical
                CA:TRUE
    Signature Algorithm: sha256WithRSAEncryption
         3b:83:25:eb:fe:e9:b3:82:bf:bb:7d:49:2e:0d:77:fc:de:44:
         4b:85:f4:82:ac:1c:31:eb:61:46:41:20:ed:5a:05:06:ce:3b:
         58:83:b4:be:15:03:72:c1:13:1e:9f:3a:03:79:7d:bc:6b:a1:
         4b:33:5f:df:fa:3e:dc:4b:7b:ee:54:f2:2e:4c:3b:3b:4a:f8:
         ec:71:3e:bb:43:7e:76:e5:5d:56:fa:21:6e:04:2a:14:e7:59:
         eb:12:ed:1d:96:9c:e5:ad:ce:a4:50:5c:a1:54:be:80:67:dd:
         07:24:2d:5d:68:f5:ea:b3:60:81:3f:6a:86:f8:cf:41:9a:55:
         a9:c0:f4:f4:b3:cd:b5:4f:b1:7e:fd:44:20:f5:07:b3:66:57:
         47:0a:11:0e:c8:ac:2a:e1:2f:b1:25:0d:5f:c6:94:da:ed:55:
         d1:e3:63:49:b0:cf:d8:ae:fb:46:09:bf:1b:dc:1c:34:c4:46:
         2d:74:e9:bd:bc:29:7c:c9:cf:e3:f9:fe:1c:a0:db:0a:91:5f:
         37:48:7d:a5:c0:8d:6d:24:ba:ae:67:c7:22:54:00:bc:31:0f:
         ff:29:cf:be:ee:36:de:30:e9:67:c9:a1:20:cc:e9:7a:c0:22:
         18:75:e4:ad:ed:66:0f:44:cc:19:80:67:fe:43:8c:ad:11:72:
         60:b2:69:7c

CF API에 대한 접근도 구성해야 해요. 이를 위해 이제 cf 명령줄 도구를 사용할 거예요.

먼저, 앞서 CF에 인증하는 데 사용한 metadata 파일이 있는 디렉토리에서 $ pcf target을 실행하세요. 이렇게 하면 cf 도구가 pcf 도구와 같은 위치를 가리키게 돼요. 다음으로 $ cf api를 실행해 Vault가 사용할 API 엔드포인트를 확인하세요.

다음으로 Vault가 사용할 사용자를 구성하세요. 이 플러그인은 Org Manager 수준 권한으로 테스트되었지만, 더 낮은 수준 권한도 사용 가능할 수 있어요.

$ cf create-user vault pa55w0rd
$ cf orgs
$ cf org-users my-example-org
$ cf set-org-role vault my-example-org OrgManager

구체적으로 여기서 만든 vault 사용자는 다음 API 호출을 수행할 수 있어야 해요.

  • Method: "GET", endpoint: "/v2/info"
  • Method: "POST", endpoint: "/oauth/token"
  • Method: "GET", endpoint: "/v2/apps/$APP_ID"
  • Method: "GET", endpoint: "/v2/organizations/$ORG_ID"
  • Method: "GET", endpoint: "/v2/spaces/$SPACE_ID"

다음으로 PCF는 TLS에 자체 서명 인증서를 자주 사용하며, 처음에 다음 같은 오류로 거부될 수 있어요.

x509: certificate signed by unknown authority

이 오류를 만나면 먼저 다음으로 CF가 API에 사용하는 인증서의 사본을 얻어야 해요.

$ openssl s_client - showcerts -servername domain.com -connect domain.com:443

실제 호출의 예시:

$ openssl s_client -showcerts -servername api.sys.somewhere.cf-app.com -connect api.sys.somewhere.cf-app.com:443

응답의 일부에는 인증서가 포함되며, 이를 복사해 올바르게 형식화된 로컬 파일에 붙여 넣어야 해요. 인증서가 어떻게 보여야 하고 openssl로 파싱될 수 있는지 확인하는 방법의 예시는 위 ca.crt를 참고하세요. 아래 워크스루는 이 파일을 cfapi.crt라고 이름 지었다고 가정해요.

워크스루 (Walkthrough)

위에서 설명한 정보를 얻은 후 Vault 운영자는 CF 인증 방식을 다음과 같이 구성해요.

$ vault auth enable cf

$ vault write auth/cf/config \
      [email protected] \
      cf_api_addr=https://api.dev.cfdev.sh \
      cf_username=vault \
      cf_password=pa55w0rd \
      [email protected]

$ vault write auth/cf/roles/my-role \
    bound_application_ids=2d3e834a-3a25-4591-974c-fa5626d5d0a1 \
    bound_space_ids=3d2eba6b-ef19-44d5-91dd-1975b0db5cc9 \
    bound_organization_ids=34a878d0-c2f9-4521-ba73-a9f664e82c7bf \
    policies=my-policy

구성되면, CF_INSTANCE_CERTCF_INSTANCE_KEY에 대한 실제 값을 포함한 CF 인스턴스에서 다음으로 로그인할 수 있어요.

$ vault login -method=cf role=test-role

CF의 경우 구성되면 사용자를 대신해 Vault 토큰을 얻는 데 사용할 수 있는 에이전트도 제공해요.

CF API와 상호 TLS 활성화하기

CF API는 클라이언트와 상호 TLS를 요구하도록 구성될 수 있어요. 이 플러그인은 cf_api_mutual_tls_certificatecf_api_mutual_tls_key 구성 속성을 설정해 상호 TLS를 지원해요.

$ vault write auth/cf/config \
      [email protected] \
      cf_api_addr=https://api.dev.cfdev.sh \
      cf_username=vault \
      cf_password=pa55w0rd \
      [email protected] \
      [email protected] \
      [email protected]

제공된 인증서는 CF API가 신뢰하는 인증 기관이 서명해야 해요. 그러한 인증서를 얻는 것은 Cloud Foundry 배포의 구체적 사항에 달려 있어요.

유지 관리 (Maintenance)

테스트에서 CF 인스턴스 신원 CA 인증서가 3년에 만료되도록 설정된 것을 발견했어요. 일부 CF 문서는 4년마다 만료된다고 해요. 얼마나 길든, 어느 시점에는 곧 만료될 CA 인증서와 현재 또는 곧 유효한 CA 인증서—CA 인증서를 하나 더 추가해야 할 수 있어요.

$ CURRENT=$(cat /path/to/current-ca.crt)
$ FUTURE=$(cat /path/to/future-ca.crt)
$ vault write auth/vault-plugin-auth-cf/config identity_ca_certificates="$CURRENT" identity_ca_certificates="$FUTURE"

Vault가 identity_ca_certificates어느 하나와 일치하는 CF_INSTANCE_CERT를 받으면 인스턴스 인증서가 유효한 것으로 간주돼요.

cf_api_trusted_certificates를 갱신하는 데도 비슷한 접근 방식이 가능해요.

한눈에 보는 문제 해결

x509: certificate signed by unknown authority를 포함한 오류를 받으면 위에서 설명한 대로 cf_api_trusted_certificates를 설정하세요.

CF_INSTANCE_CERT를 사용해 인증할 수 없다면 먼저 CF_INSTANCE_CERT의 현재 사본을 얻어 로컬 환경에 복사하세요. 그런 다음 각각이 뚜렷한 인증서인 두 파일로 나눠요. 첫 번째 인증서는 보통 실제 identity.crt이고, 두 번째는 보통 intermediate.crt예요. 다음 같은 명령으로 각각이 올바르게 이름이 지정되고 형식화되었는지 확인하세요.

$ openssl x509 -in ca.crt -text -noout

그런 다음 인증서가 구성한 ca.crt에 올바르게 체인되는지 확인하세요.

$ openssl verify -CAfile ca.crt -untrusted intermediate.crt identity.crt

이것은 성공 응답을 보여 줘야 해요. 그렇지 않다면 만료된 인증서인지, 잘못된 ca.crt인지, 아니면 확인 중인 인증서와 일치하지 않는 Vault 구성인지 근본 원인을 식별하려고 시도하세요.

API

CF 인증 방식은 완전한 HTTP API를 제공해요. 자세한 내용은 CF Auth API 문서를 참고해 주세요.

Terraform

Vault Terraform 프로바이더로 CF 인증 리소스를 프로그래밍 방식으로 관리할 수 있어요. 자세한 내용은 Terraform Registry 문서를 참고하세요.

더 알아보기 (Learn more)

  • CF 인증 방식 전체 API는 CF Auth API 문서를 참고하세요.
  • Cloud Foundry 인스턴스 신원에 대한 자세한 내용은 CF 문서를 참고하세요.