GoogleCloudPlatform / deploymentmanager-samples

Deployment Manager samples and templates.
Apache License 2.0
937 stars 718 forks source link

Can't grant permissions on secrets #574

Open m0ar opened 3 years ago

m0ar commented 3 years ago

In our new deployments, I've been trying to assign secretmanager.secretAccessor on a specific secret to a given service account.

Is this an impossible feat? I've managed to create a type provider for the secret manager API, but cannot assign the required permissions.

This is a minimal deployment of the secret:

resources:
  # Service account needing secretAccessor
  - name: account-user123
    type: iam.v1.serviceAccount
    properties:
      accountId: user123
      displayName: user123

  # Create secret
  - name: secret-parent-up-auth_secret
    action: [PROJECT_ID]/secret-manager:secretmanager.projects.secrets.create
    properties:
      replication:
        automatic: {}
      parent: projects/[PROJECT_ID]
      secretId: auth_secret
    metadata:
      runtimePolicy:
        - CREATE
      dependsOn:
        - api-secretmanager
        - type-provider-secret-manager

  # Delete secret
  - name: secret-parent-down-auth_secret
    action: [PROJECT_ID]/secret-manager:secretmanager.projects.secrets.delete
    properties:
      name: projects/155387989549/secrets/auth_secret
    metadata:
      runtimePolicy:
        - DELETE
      dependsOn:
        - type-provider-secret-manager

  # Deploy secret version
  - name: secret-version-auth_secret_payload
    action: [PROJECT_ID]/secret-manager:secretmanager.projects.secrets.addVersion
    properties:
      parent: projects/[PROJECT_ID]/secrets/auth_secret
      payload:
        data: c3RhcmZpc2g=
    metadata:
      dependsOn:
        - secret-parent-up-auth_secret

  # Deploy secret manager type provider
  - name: type-provider-secret-manager
    type: gcp-types/deploymentmanager-v2beta:typeProviders
    properties:
      name: secret-manager
      descriptorUrl: https://secretmanager.googleapis.com/$discovery/rest?version=v1beta1
      options:
        inputMappings:
          - fieldName: Authorization
            location: HEADER
            value: $.concat("Bearer ", $.googleOauth2AccessToken())
m0ar commented 3 years ago

This approach does not work. Probably because the Cloud Resource Manager virtual type only refers to the project level?

  - name: iam-role-user123-secretAccessor
    type: gcp-types/cloudresourcemanager-v1:virtual.projects.iamMemberBinding
    properties:
      resource: projects/[PROJECT_NUMBER]/secrets/auth_secret
      role: roles/secretmanager.secretAccessor
      member: serviceAccount:user123@[PROJECT_ID].iam.gserviceaccount.com
    metadata:
      dependsOn:
        - account-user123
        - secret-version-auth_secret_payload

Resulting deployment error:

ERROR: (gcloud.deployment-manager.deployments.update) Error in Operation [operation-1599118517912-5ae63cb36c47e-ae5c4d90-e5270e72]: errors:
- code: CONDITION_NOT_MET
  location: /deployments/secret-test/resources/iam-role-user123-secretAccessor->$.properties->$.policy
  message: |-
    InputMapping for field [policy] for method [setIamPolicy] could not be set from input, mapping was: [$.gcpIamMemberBinding($.intent, $.inputs.policy.response, $.resource.properties)], and evaluation context was:
    {
      "deployment" : {
        "id" : 4104525605007860895,
        "name" : "secret-test"
      },
      "extensions" : {
        "EnableAdditionalJsonPathFunctions" : true,
        "EnableGoogleTypeProviderFunctionsExperiment" : true
      },
      "inputs" : {
        "policy" : {
          "error" : {
            "code" : "400",
            "message" : "{\"code\":400,\"message\":\"Request contains an invalid argument.\",\"status\":\"INVALID_ARGUMENT\",\"statusMessage\":\"Bad Request\",\"requestPath\":\"https://cloudresourcemanager.googleapis.com/v1/projects/projects%2F[PROJECT_NUMBER]%2Fsecrets%2Fauth_secret:getIamPolicy\",\"httpMethod\":\"POST\"}"
          }
        }
      },
      "intent" : "CREATE",
      "matches" : [ ],
      "project" : "[PROJECT_ID]",
      "requestId" : "993e73d8-6001-34bc-8611-b78e0f989830",
      "resource" : {
        "name" : "iam-role-user123-secretAccessor",
        "previous" : { },
        "properties" : {
          "member" : "serviceAccount:user123@[PROJECT_ID].iam.gserviceaccount.com",
          "resource" : "projects/[PROJECT_NUMBER]/secrets/auth_secret",
          "role" : "roles/secretmanager.secretAccessor"
        },
        "self" : { }
      }
    }
    Error was:
    Parameter for gcpIamMemberBinding at position 1 is not of type map, value was [null]
m0ar commented 3 years ago

Adding the role directly to the secret does not work either, since it's an action and not an actual type:

  - name: secret-parent-up-auth_secret
    action: [PROJECT_ID]/secret-manager:secretmanager.projects.secrets.create
    properties:
      replication:
        automatic: {}
      parent: projects/[PROJECT_ID]
      secretId: auth_secret
    metadata:
      runtimePolicy:
        - CREATE
      dependsOn:
        - api-secretmanager
        - type-provider-secret-manager
    accessControl:
      gcpIamPolicy:
        bindings:
          - role: roles/secretmanager.secretaccessor
            members:
              - serviceAccount:user123@[PROJECT_ID].iam.gserviceaccount.com

Error:

ERROR: (gcloud.deployment-manager.deployments.update) Error in Operation [operation-1599118883118-5ae63e0fb5ddb-8498faf3-33ecf823]: errors:
- code: INVALID_FIELD_VALUE
  location: /deployments/secret-test/manifests/manifest-1599118883319->$.expandedConfig->$.resources[2].accessControl
  message: accessControl is not supported for actions

Is there a way to deploy the secret using an actual type, possibly enabling assigning the role in this way?

m0ar commented 3 years ago

What does work, but gives access to all project secrets (which is obviously too generous):

  - name: iam-projectRole-user123-secretAccessor
    type: gcp-types/cloudresourcemanager-v1:virtual.projects.iamMemberBinding
    properties:
      resource: [PROJECT_ID]
      role: roles/secretmanager.secretAccessor
      member: serviceAccount:user123@[PROJECT_ID].iam.gserviceaccount.com
    metadata:
      dependsOn:
        - account-user123
        - secret-version-auth_secret_payload
ocsig commented 3 years ago

Please note, actions is an ALPHA feature of DM.

type: gcp-types/cloudresourcemanager-v1:virtual.projects.iamMemberBinding gives project wide iam bindings. There are a few virtual types for resource level bindings for example gcp-types/cloudfunctions-v1:virtual.projects.locations.functions.iamMemberBinding for Cloud Functions. As of today there is no such virtual type for secrets.

What should work for you is to call the action: [PROJECT_ID]/secret-manager:secretmanager.projects.secrets.getIamPolicy and then action: [PROJECT_ID]/secret-manager:secretmanager.projects.secrets.setIamPolicy. (For reference, here is the old implementation. )

m0ar commented 3 years ago

@ocsig Got it, thanks for the insights :heart: