리소스 기반 액세스 구성

이 주제에서는 ID 및 액세스 관리(IAM) 정책에서 조건부 역할 binding을 사용하여 특정 리소스에 대해 액세스를 관리하는 방법을 설명합니다. 조건 표현식에서 리소스 속성을 사용하여 리소스 이름, 리소스 유형, Google Cloud 서비스를 기반으로 역할 binding의 하위 범위를 부여할 수 있습니다.

시작하기 전에

  • IAM 조건부 역할 binding의 기본 사항을 이해하려면 IAM 조건 개요를 읽어보세요.
  • 조건 표현식에서 사용할 수 있는 리소스 속성을 검토하세요.
  • 리소스 이름 속성은 다음 Google Cloud 서비스에 대한 액세스를 제어할 수 있습니다.
    • Compute Engine
    • Cloud Key Management Service
    • Cloud Storage
    • Cloud Spanner

리소스 이름 프리픽스를 기반으로 리소스 그룹에 액세스 권한 부여

조건부 역할 binding을 사용하면 이름이 특정 문자열로 시작하는 Compute Engine 가상 머신(VM) 인스턴스와 같이 리소스 이름이 프리픽스와 일치하는 리소스 구성원에게 액세스 권한을 부여할 수 있습니다. 리소스 이름 프리픽스는 일반적으로 특정 기능을 위한 리소스 또는 특정 속성이 있는 리소스를 그룹화하는 데 사용됩니다.

다음 예시를 살펴보겠습니다. 소프트웨어 회사 ExampleCo는 민감한 건강 관리 데이터에 대해 작동하는 특정 VM 인스턴스에서 워크로드를 실행합니다. 민감하지 않은 다른 워크로드는 동일한 프로젝트에서 실행되어야 하며 ExampleCo는 개발자가 민감한 정보에 대해 작동하는 VM 인스턴스에 제한적으로 액세스할 수 있도록 설정하려고 합니다. 이 목표를 달성하기 위해 데이터에 민감한 VM 인스턴스의 이름에는 sensitiveAccess 프리픽스를 포함하고 기타 VM 인스턴스의 이름에는 devAccess 프리픽스를 포함합니다. 그런 다음 조건부 역할 binding을 사용하여 개발자에게 sensitiveAccess VM 인스턴스에 대한 액세스 권한을 부여하지 않고도 일반 devAccess VM 인스턴스에 대한 생산성을 유지하도록 합니다.

resource.name 조건 속성만 사용하여 액세스를 관리할 수도 있지만 resource.type 속성과 resource.service 속성도 사용하는 것이 일반적입니다. 이러한 추가 속성을 사용하면 유사한 이름의 다른 리소스 유형에 대한 액세스에 조건이 영향을 미칠 가능성이 낮아집니다. 이 섹션의 예시에서는 resource.name 속성과 resource.type 속성을 모두 사용하여 액세스를 제어합니다.

프로젝트의 Compute Engine 디스크 및 인스턴스에 이름 프리픽스를 기반으로 액세스 권한을 부여하려면 다음 안내를 따르세요.

Console

  1. Cloud Console에서 IAM 페이지로 이동합니다.

    IAM 페이지로 이동

  2. 구성원 목록에서 원하는 구성원을 찾고 버튼을 클릭합니다.

  3. 권한 수정 패널에서 조건을 구성할 역할을 찾습니다. 그런 다음 조건에서 조건 추가를 클릭합니다.

  4. 조건 수정 패널에서 조건의 제목 및 설명(선택사항)을 입력합니다.

  5. 조건 빌더 또는 조건 편집기를 사용하여 조건 표현식을 추가할 수 있습니다. 조건 빌더에서는 표현식에 대해 원하는 조건 유형, 연산자, 기타 적용 가능한 세부정보를 선택할 수 있는 대화형 인터페이스를 제공합니다. 조건 편집기에서는 CEL 구문을 사용하여 표현식을 수동으로 입력하는 텍스트 기반 인터페이스를 제공합니다.

    조건 빌더:

    1. 추가 드롭다운 메뉴를 클릭하고 그룹화된 조건을 클릭합니다.
    2. 조건 유형 드롭다운에서 리소스 > 유형을 선택합니다.
    3. 연산자 드롭다운에서 일치를 선택합니다.
    4. 리소스 유형 드롭다운에서 compute.googleapis.com/Disk를 선택합니다.
    5. 방금 입력한 조건 바로 아래 첫 번째 추가 버튼을 클릭하여 표현식에 다른 절을 추가합니다.
    6. 조건 유형 드롭다운에서 리소스 > 이름을 선택합니다.
    7. 연산자 드롭다운에서 다음으로 시작을 선택합니다.
    8. 필드에 리소스 이름을 적절한 형식으로 입력합니다(예: 이름이 devAccess로 시작하는 디스크의 경우 projects/project-123/zones/us-central1-a/disks/devAccess).
    9. 각 조건 유형의 왼쪽에서 And를 클릭하여 두 절이 모두 true인지 확인합니다.
    10. 저장 버튼 바로 위에 있는 추가 버튼을 클릭하여 그룹화된 다른 조건 집합을 추가합니다.
    11. 조건 유형 드롭다운에서 리소스 > 유형을 선택합니다.
    12. 연산자 드롭다운에서 일치를 선택합니다.
    13. 리소스 유형 드롭다운에서 compute.googleapis.com/Instance를 선택합니다.
    14. 방금 입력한 조건 바로 아래의 첫 번째 추가 버튼을 클릭하여 표현식에 다른 절을 추가합니다.
    15. 조건 유형 드롭다운에서 리소스 > 이름을 선택합니다.
    16. 연산자 드롭다운에서 다음으로 시작을 선택합니다.
    17. 필드에 리소스 이름을 적절한 형식으로 입력합니다(예: 이름이 devAccess로 시작하는 인스턴스의 경우 projects/project-123/zones/us-central1-a/instances/devAccess).
    18. 각 조건 유형의 왼쪽에서 And를 클릭하여 두 절이 모두 true인지 확인합니다.
    19. 저장 버튼 바로 위에 있는 추가 버튼을 클릭하여 세 번째 그룹화된 조건 집합을 추가합니다.
    20. 이 조건이 다른 리소스에 영향을 주지 않도록 하려면 다음 절도 추가합니다. 조건 유형 드롭다운에서 리소스 > 유형을 선택합니다.
    21. 연산자 드롭다운에서 다름을 선택합니다.
    22. 리소스 유형 드롭다운에서 compute.googleapis.com/Disk를 선택합니다.
    23. 방금 입력한 조건 바로 아래의 첫 번째 추가 버튼을 클릭하여 표현식에 다른 절을 추가합니다.
    24. 조건 유형 드롭다운에서 리소스 > 유형을 선택합니다.
    25. 연산자 드롭다운에서 다름을 선택합니다.
    26. 리소스 유형 드롭다운에서 compute.googleapis.com/Instance를 선택합니다.
    27. 각 조건 유형의 왼쪽에서 And를 클릭하여 두 절이 모두 true인지 확인합니다.
    28. 작업이 완료되면 조건 빌더가 다음과 유사하게 표시됩니다.

    29. 저장을 클릭하여 조건을 적용합니다.

    30. 조건 수정 패널이 닫히면 권한 수정 패널에서 저장을 다시 클릭하여 IAM 정책을 업데이트합니다.

    조건 편집기:

    1. 조건 편집기 탭을 클릭하고 다음 표현식을 입력합니다.

      (resource.type == "compute.googleapis.com/Disk" &&
      resource.name.startsWith("projects/project-123/regions/us-central1/disks/devAccess")) ||
      (resource.type == "compute.googleapis.com/Instance" &&
      resource.name.startsWith("projects/project-123/zones/us-central1-a/instances/devAccess")) ||
      (resource.type != "compute.googleapis.com/Disk" &&
      resource.type != "compute.googleapis.com/Instance")
    2. 표현식을 입력한 후 오른쪽 상단 텍스트 상자 위에 있는 린터 실행을 클릭하여 CEL 구문을 린트할 수도 있습니다.

    3. 저장을 클릭하여 조건을 적용합니다.

    4. 조건 수정 패널이 닫히면 권한 수정 패널에서 저장을 다시 클릭하여 IAM 정책을 업데이트합니다.

gcloud 명령어

IAM 정책은 읽기-수정-쓰기 패턴을 통해 설정됩니다.

gcloud projects get-iam-policy 명령어를 실행하여 프로젝트의 현재 IAM 정책을 가져옵니다. 다음 예시에서는 정책의 JSON 버전이 디스크의 경로로 다운로드됩니다.

명령어:

gcloud projects get-iam-policy project-id --format=json > filepath

IAM 정책의 JSON 형식이 다운로드됩니다.

{
  "bindings": [
    {
      "members": [
        "user:project-owner@example.com"
      ],
      "role": "roles/owner"
    },
    {
      "members": [
        "group:devs@example.com"
      ],
      "role": "roles/compute.instanceAdmin"
    }
  ],
  "etag": "BwWKmjvelug=",
  "version": 1
}

리소스 이름 프리픽스 조건으로 정책을 구성하려면 다음 강조표시된 조건 표현식을 추가합니다. 버전 263.0.0 이상의 gcloud 도구를 사용하지 않는 경우 version 값을 3으로 업데이트했는지 확인합니다. 최신 버전의 gcloud 도구를 사용하면 최대 정책 값이 자동으로 설정됩니다.

{
  "bindings": [
    {
      "members": [
        "user:project-owner@example.com"
      ],
      "role": "roles/owner"
    },
    {
      "members": [
        "group:devs@example.com"
      ],
      "role": "roles/compute.instanceAdmin",
      "condition": {
          "title": "Dev_access_only",
          "description": "Only access to devAccess* VMs",
          "expression":
            "(resource.type == 'compute.googleapis.com/Disk' &&
            resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
            (resource.type == 'compute.googleapis.com/Instance' &&
            resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
            (resource.type != 'compute.googleapis.com/Instance' &&
            resource.type != 'compute.googleapis.com/Disk')"
      }
    }
  ],
  "etag": "BwWKmjvelug=",
  "version": 3
}

그런 다음 gcloud projects set-iam-policy 명령어를 실행하여 새 정책을 설정합니다.

gcloud projects set-iam-policy project-id filepath

새 조건부 역할 binding은 다음과 같은 방식으로 devs@example.com 권한을 부여합니다.

  • 리소스 이름이 devAccess로 시작하는 경우에만 모든 디스크 및 인스턴스 권한이 부여됩니다.

  • 다른 모든 리소스 유형에 인스턴스 관리자 역할의 다른 모든 권한이 부여됩니다.

REST API

읽기-수정-쓰기 패턴을 사용하여 특정 리소스에 대해 액세스를 허용합니다.

먼저 프로젝트에 대해 IAM 정책을 읽습니다.

Resource Manager API의 projects.getIamPolicy 메서드가 프로젝트의 IAM 정책을 가져옵니다.

아래의 요청 데이터를 사용하기 전에 다음을 바꿉니다.

  • project-id: Google Cloud 프로젝트 ID
  • policy-version: 반환할 정책 버전입니다. 요청에는 정책 버전 3인 최신 정책 버전이 지정되어야 합니다. 자세한 내용은 정책을 가져올 때 정책 버전 지정을 참조하세요.

HTTP 메서드 및 URL:

POST https://cloudresourcemanager.googleapis.com/v1/projects/project-id:getIamPolicy

JSON 요청 본문:

{
  "options": {
    "requestedPolicyVersion": policy-version
  }
}

요청을 보내려면 다음 옵션 중 하나를 펼칩니다.

다음과 비슷한 JSON 응답이 표시됩니다.

{
  "version": 1,
  "etag": "BwWKmjvelug=",
  "bindings": [
    {
      "role": "roles/owner",
      "members": [
        "user:project-owner@example.com"
      ]
    },
    {
      "members": [
        "group:devs@example.com"
      ],
      "role": "roles/compute.instanceAdmin"
    }
  ]
}

다음으로 특정 리소스에 대해 액세스를 허용하도록 정책을 수정합니다. version 필드를 3 값으로 변경합니다.

{
  "version": 3,
  "etag": "BwWKmjvelug=",
  "bindings": [
    {
      "role": "roles/owner",
      "members": [
        "user:project-owner@example.com"
      ]
    },
    {
      "role": "roles/compute.instanceAdmin",
      "members": [
        "group:devs@example.com"
      ],
      "condition": {
          "title": "Dev_access_only",
          "description": "Only access to devAccess* VMs",
          "expression":
            "(resource.type == 'compute.googleapis.com/Disk' &&
            resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
            (resource.type == 'compute.googleapis.com/Instance' &&
            resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
            (resource.type != 'compute.googleapis.com/Instance' &&
            resource.type != 'compute.googleapis.com/Disk')"
      }
    }
  ]
}

마지막으로 업데이트된 정책을 작성합니다.

Resource Manager API의 projects.setIamPolicy 메서드는 요청의 정책을 프로젝트의 새 IAM 정책으로 설정합니다.

아래의 요청 데이터를 사용하기 전에 다음을 바꿉니다.

  • project-id: Google Cloud 프로젝트 ID

HTTP 메서드 및 URL:

POST https://cloudresourcemanager.googleapis.com/v1/projects/project-id:setIamPolicy

JSON 요청 본문:

{
  "policy": {
    "version": 3,
    "etag": "BwWKmjvelug=",
    "bindings": [
      {
        "role": "roles/owner",
        "members": [
          "user:project-owner@example.com"
        ]
      },
      {
        "role": "roles/compute.instanceAdmin",
        "members": [
          "group:devs@example.com"
        ],
        "condition": {
          "title": "Dev_access_only",
          "description": "Only access to devAccess* VMs",
          "expression":
            "(resource.type == 'compute.googleapis.com/Disk' &&
            resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
            (resource.type == 'compute.googleapis.com/Instance' &&
            resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
            (resource.type != 'compute.googleapis.com/Instance' &&
            resource.type != 'compute.googleapis.com/Disk')"
        }
      }
    ]
  }
}

요청을 보내려면 다음 옵션 중 하나를 펼칩니다.

응답에는 업데이트된 정책이 포함됩니다.


리소스 이름에서 값 추출

이전 예시는 리소스 이름 또는 리소스 이름의 시작과 다른 값 간의 부울 비교를 보여줍니다. 그러나 값을 리소스 이름의 시작 부분이 아닌 특정 부분과 비교해야 하는 경우도 있습니다.

extract() 함수를 사용하고 추출 템플릿을 지정하여 리소스 이름의 관련 부분을 문자열로 추출할 수 있습니다. 필요하다면 추출된 문자열을 타임스탬프와 같은 다른 유형으로 변환할 수 있습니다. 리소스 이름에서 값을 추출한 다음 해당 값을 다른 값과 비교할 수 있습니다.

다음 예시에서는 extract() 함수를 사용하는 조건 표현식을 보여줍니다. extract() 함수에 대한 자세한 내용은 IAM 조건 속성 참조를 참조하세요.

예시: 지난 30일 동안의 주문 일치

주문 정보를 여러 Cloud Storage 버킷에 저장하고 각 버킷의 객체를 날짜별로 정리한다고 가정합니다. 일반적인 객체 이름은 다음 예시와 비슷할 수 있습니다.

projects/_/buckets/acme-orders-aaa/data_lake/orders/order_date=2019-11-03/aef87g87ae0876

지난 30일 동안의 모든 주문과 일치시키려는 경우입니다. 다음 조건은 이 주문과 일치합니다. duration()date() 함수를 사용하여 요청 시간에서 30일(2,592,000초)을 뺀 다음 타임스탬프를 주문 날짜와 비교합니다.

request.time - duration('2592000s') < date(resource.name.extract('/order_date={date_str}/'))

date()duration() 함수에 대한 자세한 내용은 날짜/시간 속성 참조를 참조하세요.

예시: 모든 위치에서 Compute Engine VM 일치

이름이 dev-로 시작하는 모든 위치에서 모든 Compute Engine VM과 일치해야 한다고 가정합니다. VM의 리소스 이름은 projects/project-id/zones/zone-id/instances/instance-name과 유사한 형식을 사용합니다. 인스턴스 이름이 문자열 dev-로 시작하는 경우 다음 조건은 true로 평가됩니다.

resource.name.extract('/instances/{name}/').startsWith('dev-')

중괄호 안의 텍스트는 비교를 위해 추출되는 리소스 이름의 일부를 식별합니다. 이 예시에서 추출 템플릿은 문자열 /instances/의 첫 번째 어커런스와 문자열 /의 다음 어커런스 사이 문자를 추출합니다.

리소스 기반 조건의 중요한 사용 고려사항

리소스 기반 조건을 추가할 때는 부여된 권한이 조건의 영향을 받는 방식을 고려해야 합니다.

커스텀 역할

커스텀 역할이 포함된 다음 예시를 참조합니다. 관리자가 VM 인스턴스 생성을 위한 액세스 권한을 부여하지만 이름 프리픽스가 같은 디스크를 사용하여 리소스 이름이 이름 프리픽스 staging으로 시작하는 프로젝트에서만 사용자가 VM 인스턴스를 만들 수 있는 커스텀 역할을 만들려고 합니다.

이 작업을 수행하려면 부여된 역할에 디스크 및 인스턴스 리소스 유형에 대한 권한을 의미하는 VM 인스턴스를 만들기 위한 필수 권한이 포함되는지 확인합니다. 그런 다음 조건 표현식에서 리소스 이름에 디스크와 인스턴스가 모두 있는지 확인합니다. 이 두 유형이 아니라면 역할에 다른 권한이 부여되지 않습니다.

다음 조건 표현식은 예기치 않은 동작을 초래합니다. Compute Engine VM에서 작동하는 권한이 차단됩니다.

"expression":
"resource.type == 'compute.googleapis.com/Disk' &&
 resource.name.startsWith('projects/project-123/regions/us-central1/disks/staging')"

다음 조건 표현식은 디스크와 인스턴스를 모두 포함하며 두 유형의 리소스 이름을 기반으로 액세스를 관리합니다.

"expression":
"(resource.type == 'compute.googleapis.com/Disk' &&
  resource.name.startsWith('projects/project-123/regions/us-central1/disks/staging')) ||
 (resource.type == 'compute.googleapis.com/Instance' &&
  resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/staging'))"

다음 조건 표현식은 디스크와 인스턴스를 모두 포함하며 두 유형의 리소스 이름을 기반으로 액세스를 관리합니다. 다른 리소스 유형의 경우 조건 표현식은 리소스 이름에 관계없이 역할을 부여합니다.

"expression":
"(resource.type == 'compute.googleapis.com/Disk' &&
  resource.name.startsWith('projects/project-123/regions/us-central1/disks/staging')) ||
 (resource.type == 'compute.googleapis.com/Instance' &&
  resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/staging')) ||
 (resource.type != 'compute.googleapis.com/Disk' &&
  resource.type != 'compute.googleapis.com/Instance')"

상위 요소 전용 권한

Google Cloud의 리소스 계층 구조에서 하위 리소스에 영향을 미치는 역할의 일부 권한은 상위 수준에서만 적용됩니다. 예를 들어 Cloud KMS의 암호화 키를 나열하려면 키 자체가 아닌 암호화 키가 포함된 키링에 대한 cloudkms.cryptokeys.list 권한이 사용자에게 부여되어야 합니다. 이러한 종류의 권한을 상위 요소 전용 권한이라 하며 list 작업에만 적용됩니다.

조건을 사용하는 경우 *.*.list 권한에 대한 액세스 권한을 올바르게 부여하려면 조건 표현식은 나열할 대상 리소스의 상위 리소스 유형에 따라 resource.serviceresource.type 속성을 설정해야 합니다.

다음 예시를 고려하세요. 위의 Compute Engine 예시를 사용하면, 다음 표현식은 권한을 검사하는 리소스의 resource.type 속성 값이 cloudresourcemanager.googleapis.com/Project이기 때문에 compute.disks.listcompute.instances.list 권한에 액세스하지 못하게 합니다.

"expression":
"(resource.type == 'compute.googleapis.com/Disk' &&
  resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
 (resource.type == 'compute.googleapis.com/Instance' &&
  resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess'))"

일반적으로 이 list 권한은 리소스에 대한 일반 작업의 다른 권한과 함께 부여됩니다. 이 경우 부여 범위를 늘리려면 cloudresourcemanager.googleapis.com/Project 유형의 범위만 확장하거나 인스턴스 또는 디스크 유형이 아닌 다른 모든 권한으로 범위를 확장할 수 있습니다.

"expression":
"(resource.type == 'compute.googleapis.com/Disk' &&
  resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
 (resource.type == 'compute.googleapis.com/Instance' &&
  resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
 resource.type == 'cloudresourcemanager.googleapis.com/Project'"

또는

"expression":
"(resource.type == 'compute.googleapis.com/Disk' &&
  resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
 (resource.type == 'compute.googleapis.com/Instance' &&
  resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
 (resource.type != 'compute.googleapis.com/Disk' &&
  resource.type != 'compute.googleapis.com/Instance')"