IAP(Identity-Aware Proxy)를 사용하여 컨텍스트 인식 액세스 설정

이 가이드에서는 액세스 수준ID 및 액세스 관리(IAM) 조건 프레임워크를 사용하여 IAP(Identity-Aware Proxy) 액세스 정책을 확장하는 방법을 설명합니다. 액세스 수준을 사용하면 IP 주소 및 최종 사용자 장치 속성을 기준으로 리소스에 대한 액세스를 제한할 수 있습니다. IAM 조건을 사용하면 URL 호스트, 경로, 날짜, 시간을 기준으로 액세스를 제한할 수 있습니다.

예를 들어 정책 구성에 따라 중요 보안 앱에서 다음을 수행할 수 있습니다.

  • 회사 네트워크에서 신뢰할 수 있는 회사 기기를 사용하는 경우 모든 직원에게 액세스 권한을 부여합니다.
  • 원격 액세스 그룹의 직원에게는 어떤 네트워크에서든 보안 암호 및 최신 패치 수준이 적용된 신뢰할 수 있는 회사 기기를 사용하는 경우에 액세스 권한을 부여합니다.
  • 권한이 지정된 액세스 그룹의 직원에게 URL 경로가 /admin으로 시작하는 경우에만 액세스 권한을 부여합니다.

시작하기 전에

시작하기 전에 다음이 필요합니다.

  • 개인 또는 그룹 액세스를 추가하려는 IAP 보안 앱
  • 액세스 권한을 부여하려는 사용자 또는 그룹 이름

액세스 수준 설정

IP 주소 또는 최종 사용자 기기 속성을 기준으로 액세스를 제한하려면 액세스 수준을 만들어야 합니다. 액세스 수준을 만드는 방법을 보려면 Access Context Manager 가이드를 참조하세요. IAP는 액세스 수준 이름을 사용하여 이를 IAP 보안 앱과 연결합니다.

서비스 계정 만들기

API를 사용해서 액세스 수준을 사용하고 IAM 정책을 업데이트하려면 프로젝트에 대해 인증된 서비스 계정이 필요합니다.

  1. 앱이 배포된 프로젝트에서 새 서비스 계정을 만듭니다.
  2. gcloud auth activate-service-account를 사용하여 새 서비스 계정을 인증합니다.

사용자 인증 정보 파일 다운로드

API를 사용하여 IAM 정책을 업데이트하려면 새 서비스 계정의 JSON 사용자 인증 정보 파일을 다운로드해야 합니다. JSON 사용자 인증 정보 파일을 다운로드하려면 다음 안내를 따르세요.

  1. 서비스 계정 페이지로 이동합니다.
    서비스 계정 페이지로 이동

  2. 서비스 계정의 이메일 주소를 클릭합니다.

  3. 수정을 클릭합니다.

  4. 키 만들기를 클릭합니다.

  5. 키 유형으로 JSON을 선택합니다.

  6. 만들기를 클릭하고 표시된 확인 창을 닫아서 새 키를 만듭니다.

JSON 사용자 인증 정보 파일이 이제 다운로드되었습니다.

IAM 정책 수정

IAP 보안 앱에는 IAP 역할을 앱에 결합하는 IAM 정책이 있습니다.

IAM 정책에 IAM 조건부 바인딩을 추가하면 요청 속성에 따라 리소스에 대한 액세스가 더욱 제한됩니다. 이러한 요청 속성에는 다음이 포함됩니다.

  • 액세스 수준
  • URL 호스트/경로
  • 날짜/시간

IAM 조건부 binding에서 지정된 request.hostrequest.path와 비교되는 요청 값은 정확하게 일치해야 합니다. 예를 들어 /internal admin으로 시작하는 경로에 대한 액세스를 제한할 경우 /internal%20admin으로 이동하여 제한을 우회할 수 있습니다. 호스트 이름 및 경로 조건에 대한 자세한 내용은 호스트 이름 및 경로 조건 사용을 참조하세요.

아래 프로세스에 따라 IAM 정책에서 조건부 바인딩을 추가합니다.

Console

Cloud Console을 사용하여 조건부 binding을 추가하려면 다음 안내를 따르세요.

  1. IAP 관리자 페이지로 이동하세요.

    IAP 관리자 페이지로 이동

  2. IAM 권한을 업데이트하려는 리소스 옆의 체크박스를 선택합니다.

  3. 오른쪽 정보 패널에서 구성원 추가를 클릭합니다.

  4. 새 구성원 상자에서 역할을 할당하려는 구성원을 입력합니다.

  5. 역할 선택 드롭다운 목록에서 IAP 보안 웹 앱 사용자 역할을 선택하고 구성원이 리소스에 액세스하기 위해 충족해야 하는 액세스 수준 조건을 지정합니다.

    • 기존 액세스 수준을 지정하려면 액세스 수준 드롭다운 목록에서 이를 선택합니다. IAP 보안 웹 앱 사용자 역할을 선택해야 하고, 기존 액세스 수준을 볼 수 있는 조직 수준의 권한이 있어야 합니다. 다음 역할 중 하나를 부여 받아야 합니다.
      • Access Context Manager 관리자
      • Access Context Manager 편집자
      • Access Context Manager 리더
    • 액세스 수준을 만들고 관리하려면 Access Context Manager를 사용하세요.
  6. 구성원에 역할을 더 추가하려면 다른 역할 추가를 클릭합니다.

  7. 역할 추가가 완료되었으면 저장을 클릭합니다.

    이제 리소스에 조건부 결합이 추가되었습니다.

조건부 결합을 삭제하려면 다음 안내를 따르세요.

  1. IAP 관리자 페이지로 이동하세요.

    IAP 관리자 페이지로 이동

  2. 구성원의 IAM 역할을 삭제하려는 리소스 옆의 체크박스를 선택합니다.

  3. 역할/구성원 아래의 오른쪽 정보 패널에서 구성으로부터 삭제하려는 역할을 클릭합니다.

  4. 구성원 옆의 삭제 를 클릭합니다.

  5. 표시된 구성원의 역할을 삭제할까요? 대화상자에서 삭제를 클릭합니다. 선택된 리소스의 구성원에서 상속되지 않는 모든 역할을 삭제하려면 삭제를 클릭하기 전 해당 체크박스를 선택합니다.

gcloud

현재까지는 gcloud 도구를 사용하여 프로젝트 수준의 조건부 결합만 설정할 수 있습니다.

조건부 binding을 설정하려면 아래 프로세스에 따라 프로젝트의 policy.yaml 파일을 편집하세요.

  1. 다음 gcloud 명령어를 사용하여 앱의 IAM 정책을 엽니다.

    gcloud projects get-iam-policy PROJECT_ID > policy.yaml

  2. policy.yaml 파일을 편집하여 다음을 지정합니다.

    • IAM 조건을 적용할 사용자 및 그룹
    • 리소스에 대한 액세스 권한을 부여하는 iap.httpsResourceAccessor 역할
    • IAM 조건

      다음 스니펫은 속성이 하나만 지정된 IAM 조건을 보여줍니다. 이 조건은 ACCESS_LEVEL_NAME 액세스 수준 요구사항이 충족되고 리소스 URL 경로가 /로 시작되는 경우에만 사용자 및 그룹에 액세스 권한을 부여합니다.

      ...
      - members:
      - group:EXAMPLE_GROUP@GOOGLE.COM
      - user:EXAMPLE_USER@GOOGLE.COM
      role: roles/iap.httpsResourceAccessor
      condition:
          expression: "accessPolicies/ORGANIZATION_NUMBER/accessLevels/ACCESS_LEVEL_NAME" in
                       request.auth.access_levels && request.path.startsWith("/")
          title: CONDITION_TITLE
      ...

  3. set-iam-policy 명령어를 사용하여 정책을 애플리케이션에 바인딩합니다.

    gcloud projects set-iam-policy PROJECT_ID policy.yaml

이제 IAM 정책에 조건부 바인딩이 포함됩니다.

API

앱의 policy.json 파일을 편집하려면 앱 유형에 대한 아래 프로세스를 따르세요. IAM API를 사용하여 액세스 정책을 관리하는 방법에 대한 자세한 내용은 IAP 보안 리소스 액세스 관리를 참조하세요.

애플리케이션 관련 API 단계를 수행하기 전 다음 안내를 따르세요.

  1. 서비스 계정의 사용자 인증 정보 파일을 다운로드합니다.
  2. 다음 변수를 내보냅니다.

    export PROJECT_NUM=PROJECT_NUMBER
    export IAP_BASE_URL=https://iap.googleapis.com/v1beta1/projects/${PROJECT_NUMBER}/iap_web
    # Replace with the path to your local service account's downloaded JSON file
    export JSON_CREDS=EXAMPLE.IAM.GSERVICEACCOUNT.COM.JSON
    # Replace POLICY_FILE.JSON with the name of JSON file to use for setIamPolicy
    export JSON_NEW_POLICY=POLICY_FILE.JSON
    

  3. 다음 명령어를 실행하여 Oauth2l를 사용해서 서비스 계정 사용자 인증 정보 JSON 파일을 OAuth 액세스 토큰으로 전환합니다.

    oauth2l header --json ${JSON_CREDS} cloud-platform

  4. 위 명령어를 처음 실행할 경우, 메시지가 표시되면, 다음 안내를 따르세요.

    1. 표시된 링크를 클릭하고 코드를 복사하여 확인 코드를 가져옵니다.
    2. 확인 코드를 앱 프롬프트에 붙여넣습니다.
    3. 반환된 Bearer 토큰을 복사합니다.
    4. 반환된 Bearer 토큰이 할당된 새 변수를 내보냅니다.
      export CLOUD_OAUTH_TOKEN=AUTHORIZATION_BEARER_TOKEN
  5. 이 명령어를 이전에 실행한 경우에는 다음 변수를 내보냅니다.

    export CLOUD_OAUTH_TOKEN ="$(oauth2l header --json ${JSON_CREDS} cloud-platform)"

App Engine

  1. 다음 App Engine 변수를 내보냅니다.

    # The APP_ID is usually the project ID
    export GAE_APP_ID=APP_ID
    export GAE_BASE_URL=${IAP_BASE_URL}/appengine-${GAE_APP_ID}

  2. getIamPolicy 메서드를 사용하여 App Engine 앱의 IAM 정책을 가져옵니다. 마지막에 비어 있는 데이터 비트는 curl 요청을 GET 대신 POST로 전환합니다.

    curl -i -H "${CLOUD_OAUTH_TOKEN}" ${GAE_BASE_URL}/:getIamPolicy \
         -d ''
    

  3. IAM 조건부 바인딩을 IAM 정책 JSON 파일에 추가합니다. 다음은 iap.httpsResourceAccessor 역할을 두 사용자에게 바인딩하여 IAP 보안 리소스에 대한 액세스 권한을 부여하는 편집 된 policy.json 파일의 예시입니다. ACCESS_LEVEL_NAME 액세스 수준 요구사항이 충족되고 리소스 URL 경로가 /로 시작되는 경우에만 리소스에 대한 액세스 권한을 부여하기 위해 IAM 조건이 추가됩니다. 결합별로 조건은 하나만 있을 수 있습니다.

    예시 policy.json 파일

    {
    "policy": {
    "bindings": [
    {
      "role": "roles/iap.httpsResourceAccessor",
      "members": [
          "group:EXAMPLE_GROUP@GOOGLE.COM",
          "user:EXAMPLE_USER@GOOGLE.COM"
      ],
      "condition": {
        "expression": ""accessPolicies/ORGANIZATION_NUMBER/accessLevels/ACCESS_LEVEL_NAME" in request.auth.access_levels && request.path.startsWith("/")",
        "title": "CONDITION_NAME"
      }
    }
    ]
    }
    }

  4. setIamPolicy 메서드를 사용하여 새 policy.json 파일을 설정합니다.

    curl -i -H "${CLOUD_OAUTH_TOKEN}" ${GAE_BASE_URL}:setIamPolicy \
         -d @${JSON_NEW_POLICY}

App Engine 서비스 및 버전

App Engine 서비스의 IAM 정책, 모든 버전 또는 서비스의 특정 버전을 업데이트할 수도 있습니다. 서비스의 특정 버전에 대해 이를 수행하려면 다음 안내를 따르세요.

  1. 다음 추가 변수를 내보냅니다.
    export GAE_SERVICE=SERVICE_NAME
    export GAE_VERSION=VERSION_NAME
    
  2. 내보낸 GAE_BASE_URL 변수를 업데이트합니다.
    export GAE_BASE_URL=${IAP_BASE_URL}/appengine-${GAE_APP_ID}/services/${GAE_SERVICE}/versions/${GAE_VERSION}
  3. 위에 표시된 getIamPolicysetIamPolicy 명령어를 사용하여 버전의 IAM 정책을 가져오고 설정합니다.

GKE 및 Compute Engine

  1. 백엔드 서비스의 프로젝트 ID를 내보냅니다.

    export BACKEND_SERVICE_NAME=BACKEND_SERVICE_NAME

  2. getIamPolicy 메서드를 사용하여 Compute Engine 앱의 IAM 정책을 가져옵니다. 마지막에 비어 있는 데이터 비트는 curl 요청을 GET 대신 POST로 전환합니다.

    curl -i -H "${CLOUD_OAUTH_TOKEN}" ${IAP_BASE_URL}/compute/services/${BACKEND_SERVICE_NAME}:getIamPolicy \
         -d ''

  3. IAM 조건부 바인딩을 IAM 정책 JSON 파일에 추가합니다. 다음은 iap.httpsResourceAccessor 역할을 두 사용자에게 바인딩하여 IAP 보안 리소스에 대한 액세스 권한을 부여하는 편집 된 policy.json 파일의 예시입니다. ACCESS_LEVEL_NAME 액세스 수준 요구사항이 충족되고 리소스 URL 경로가 /로 시작되는 경우에만 리소스에 대한 액세스 권한을 부여하기 위해 IAM 조건이 추가됩니다. 결합별로 조건은 하나만 있을 수 있습니다.


    예시 policy.json 파일

    {
    "policy": {
    "bindings": [
    {
    "role": "roles/iap.httpsResourceAccessor",
    "members": [
      "group":EXAMPLE_GROUP@GOOGLE.COM,
      "user:EXAMPLE_USER@GOOGLE.COM"
    ],
    "condition": {
      "expression": ""accessPolicies/ORGANIZATION_NUMBER/accessLevels/ACCESS_LEVEL_NAME" in request.auth.access_levels && request.path.startsWith("/")",
      "title": "CONDITION_NAME"
    }
    }
    ]
    }
    }

  4. setIamPolicy 메서드를 사용하여 새 policy.json 파일을 설정합니다.

    curl -i -H "Content-Type:application/json" \
         -H "$(oauth2l header --json ${JSON_CREDS} cloud-platform)" \
         ${IAP_BASE_URL}/compute/services/${BACKEND_SERVICE_NAME}:setIamPolicy \
         -d @${JSON_NEW_POLICY}

호스트 이름 및 경로 조건 사용

요청 URL의 호스트 이름과 경로를 사용하여 앱에 대한 액세스를 보호할 수 있습니다. 예를 들어 URL 경로가 /admin으로 시작하는 경우에만 request.path.startsWith IAM 조건을 사용하여 권한이 지정된 액세스 그룹의 직원에게 액세스 권한을 부여할 수 있습니다.

호스트 이름 및 경로 조건 사용에 대한 자세한 내용은 요청 속성을 참조하세요.

문자열 정규화

URL에는 호스트 이름과 경로가 있습니다. 예를 들어 URL https://sheets.google.com/create?query=param의 호스트 이름은 sheets.google.com이고 경로는 /create입니다.

백엔드는 호스트 이름과 경로를 다양한 방식으로 해석할 수 있습니다. 모호성을 없애기 위해 IAP는 정책을 확인할 때 호스트 이름과 경로 문자열을 정규화합니다.

요청에 비정규화된 경로가 있는 경우 IAP는 두 가지 정책 검사를 수행합니다. 비정규화된 경로가 정책 검사를 통과하면 IAP는 경로를 정규화하고 두 번째 정책 검사가 수행됩니다. 비정규화된 경로와 정규화된 경로가 모두 정책 검사를 통과하면 액세스 권한이 부여됩니다.

예를 들어, 요청에 /internal;some_param/admin 경로가 있으면 IAP는 먼저 비정규화된 경로(/internal)에서 정책 검사를 수행합니다. 통과하면 IAP는 정규화된 경로(/internal/admin)에서 두 번째 정책 검사를 수행합니다.

호스트 이름

호스트 이름은 다음 방법으로 정규화됩니다.

  • 마침표 제거
  • 소문자로 바꾸기
  • ASCII로 변환

비ASCII 문자를 포함하는 호스트 이름은 퓨니코딩으로 정규화됩니다. 일치하도록 호스트 이름 문자열을 퓨니코딩해야 합니다.

호스트 이름 문자열을 퓨니코딩하려면 Punycoder와 같은 변환기를 사용하세요.

다음은 정규화된 호스트 이름의 예시입니다.

  • FOO.comfoo.com으로 정규화되었습니다.
  • café.frxn--caf-dma.fr로 정규화되었습니다.

경로

경로는 다음 방법으로 정규화됩니다.

  • 경로 매개변수 삭제
  • 절대 경로에 대한 상대 경로 결정

경로 매개변수에는 ;에서 다음 / 또는 경로 끝까지의 모든 문자가 포함됩니다.

경로 섹션 시작 부분에 ..;이 포함된 요청은 유효하지 않은 것으로 간주됩니다. 예를 들어, /..;bar//bar/..;/HTTP 400: Bad Request 오류를 반환합니다.

다음은 정규화된 경로의 예시입니다.

  • /internal;some_param/admin/internal/admin으로 정규화되었습니다.
  • /a/../b/b로 정규화되었습니다.
  • /bar;param1/baz;baz;param2/bar/baz로 정규화되었습니다.

하위 도메인 끝 부분

request.host.endsWith("google.com")로 설정된 정책은 sub_domain.google.comtestgoogle.com과 모두 일치합니다. 정책이 google.com으로 끝나는 모든 하위 도메인으로 정책을 제한하려는 경우 정책을 request.host.endsWith(".google.com")으로 설정합니다.

정책을 request.host.endsWith(".google.com")으로 설정하면 sub_domain.google.com과 일치하지만 추가 .로 인해 google.com과 일치하지 않습니다.

Cloud 감사 로그 및 액세스 수준

IAP 보안 프로젝트에 대해 Cloud 감사 로그 사용 설정하면 승인되거나 승인되지 않은 액세스 요청을 확인할 수 있습니다. 아래 절차를 수행하여 요청자가 충족한 모든 액세스 수준 및 요청을 확인합니다.

  1. 프로젝트의 Cloud Console 로그 페이지로 이동합니다.
    로그 페이지로 이동
  2. 리소스 선택기 드롭다운 목록에서 리소스를 선택합니다. IAP 보안 HTTPS 리소스는 GAE 애플리케이션GCE 백엔드 서비스에 있습니다. IAP 보안 SSH 및 TCP 리소스는 GCE VM 인스턴스에 있습니다.
  3. 로그 유형 드롭다운 목록에서 data_access를 선택합니다.
    • data_access 로그 유형은 IAP에 Cloud 감사 로그를 사용 설정한 후 리소스에 대한 트래픽이 발생한 경우에만 표시됩니다.
  4. 검토하려는 액세스 날짜 및 시간을 클릭하여 확장합니다.
    • 승인된 액세스에는 파란색 i 아이콘이 있습니다.
    • 승인되지 않은 액세스에는 주황색 !! 아이콘이 있습니다.
  5. protoPayload > requestMetadata > requestAttributes > auth > accessLevels에 도달할 때까지 섹션을 클릭해서 확장하여 요청자가 충족한 액세스 수준을 확인합니다.

사용자가 충족한 모든 액세스 수준은 액세스 권한이 필요하지 않은 액세스 수준을 포함하여 요청을 표시할 때 확인 가능합니다. 승인되지 않은 요청이 확인되었다고 해서 액세스 수준이 충족되지 않았음을 나타내지는 않습니다. 이것은 요청에 표시되는 액세스 수준과 리소스의 조건을 비교하여 확인됩니다.

로그에 대한 자세한 내용은 Cloud 감사 로그 가이드를 참조하세요.