cyberark / conjur

CyberArk Conjur automatically secures secrets used by privileged users and machine identities
https://conjur.org
Other
780 stars 124 forks source link

GCE Authenticator #1711

Closed InbalZilberman closed 4 years ago

InbalZilberman commented 4 years ago

Feature Overview

The GCE auth method allows Google Compute Engine (GCE) instances running in Google Cloud Platform to authenticate to DAP/Conjur enable them to fetch secrets. We need authenticate these entities against the Google Cloud APIs.

It is a custom that GCP resources are provided with Google Cloud IAM - Cloud Identity and Access Management (IAM) are mostly handled using service accounts. Hence, we will authenticate resources according to their service account properties.

One can create a GCE even without a service account.

Process Logic for GCE

  1. Martin, conjur admin, define gce authenticator named "mygce"
- !policy
  id: conjur/authn-gce/mygce
  body:
  - !webservice

  - !variable
    id: provider-uri

  - !group apps
    annotations:
      description: Group of hosts that can authenticate using the authn-gce/<service-id> authenticator

  - !permit
    role: !group apps
    privilege: [ read, authenticate ]
    resource: !webservice
  1. Martin, conjur admin, or Eva, developer with permissions to Conjur define host
- !policy
  id: <policy-id>
  body:
    - !group

    - &hosts
      - !host
        id: myapp
        annotations:

          authn-gce/project-id: <project-id>
          authn-gce/service-account-id: <service-account-id>
          authn-gce/service-account-email: <service-account-email>

    - !grant
      role: !group
      members: *hosts

- !grant
  role: !group /conjur/authn-gce/mygce/apps
  member: !group <policy-id>

Constraints one of the following should be provided project-id OR service-account-id OR service-account-email

Some info on project_id Project ID: A customizable unique identifier for your project. The project ID is a unique, user-assigned ID that can be used by Google APIs. If you do not specify a project ID during project creation, a project ID will be generated automatically. The project ID must be a unique string of 6 to 30 lowercase letters, digits, or hyphens. It must start with a letter, and cannot have a trailing hyphen. You cannot change a project ID once it has been created.

  1. The app developer, Eva, should retrieve JWT using audience of Conjur

GCE requests its unique identity token (JWT) with format full from the metadata server and specifies the audience of the token to conjur

curl \ --header "Metadata-Flavor: Google" \ --get \ --data-urlencode "audience=conjur" \ --data-urlencode "format=full" \ "http://metadata/computeMetadata/v1/instance/service-accounts/default/identity"

  1. As a result JWT is received GCE token: eyJhbGciOiJSUzI1NiIsImtpZCI6IjRlNGViZTQ4N2Q1Y2RmMmIwMjZhM2IyMjlkODZmMGQ0MjU4NDQ5ZmUiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJo wZXIuZ3NlcnZpY2V...8vSRM1UhkbWIgTK7EE7ewbGZ0BUjMBcLyHcNPZjLebpm2dRSV4aRwwdnTdY2XxFGCOge19O8FTaF0Awv-FupLKwfTqvG6RUv49zABQGQpm uOp13XYZ6NnORNBuFG6YKs5udBSm2HVP4fyHGWMj4NMwxmKljG3xKAmrhU_xOQZt11TuTfe_vnqp7pt1gtXmdAH9Q5sHqfNODozPAkQyUqO5jmjFJ16

  2. Decrypt JWT fro GCE

{
  "aud": "http://conjur",
  "azp": "1109871298",
  "email": "716149141-compute@developer.gserviceaccount.com",
  "email_verified": true,
  "exp": 1595160638,
  "google": {
    "compute_engine": {
      "instance_creation_timestamp": 1595766,
      "instance_id": "43405087601530",
      "instance_name": "vm-for-gcp",
      "project_id": "eng-serenity-2313",
      "project_number": 7161458341,
      "zone": "us-central1-a"
    }
  },
  "iat": 1595157038,
  "iss": "https://accounts.google.com",
  "sub": "110987294251917851298"
}
  1. Call the /authn-gce/mygce POST https:///authn-gce/mygce//myapp/authenticate with JWT

Header Content-Type: application/x-www-form-urlencoded Body The body must include the GCP access token for GCE instance. jwt=eyJhbGciOiJSUzI1NiIs......uTonCA

The authenticator is expected to use the certificate of GCP to decode the JWT and then compare the host annotations to the fields in the JWT as follows:

  1. Validate the JWT with the provider (according to claim, experations....)
  2. Validate the audience is Conjur
  3. Validate that the host has the right host identity as written in the JWT
JWT field Correlated host annotation Remarks
email authn-gce/service_account_email
google/compute_engine/project_id authn-gce/project_id
sub authn-gce/service_account_id

Open issues

  1. global key pair vs service account key pair -

    1. GCE identity - from the "metadata" API

      https://cloud.google.com/compute/docs/storing-retrieving-metadata#default

      a. Uses the global Google certificate - https://www.googleapis.com/oauth2/v1/certs.

      b. IAM identity - from the service account keys API - "https://www.googleapis.com/service_accounts/v1/metadata/x509/%s?alt=json" https://cloud.google.com/iam/docs/creating-managing-service-account-keys

    2. Can we first check first (a) and if fails try (b) ?

    3. Can the provider-uri be hard coded and not need user input? maybe a global config?

    4. How do we validate the JWT?

Audit

All authentications calls should be audited.

Status API

Any new Authenticator that is added has it's status API

Logging

Are there new log files for this feature? If so, specify how they are called, where, if / how they are rotated and when they are enabled.

Support Matrix

orenbm commented 4 years ago

one of the following should be provided instance-name OR project-id OR service-account-id OR service-account-email

@InbalZilberman just to verify: we can have one and only one, correct? you can't have any combination and you can't have no constraints at all.

orenbm commented 4 years ago

The audience should be static - can be determined in design phase

@InbalZilberman again verifying that i understand correctly - the solution design should introduce a static audience (e.g conjur) and it will be documented. this audience will be provided by the user when they request a JWT and we will verify it in our code.

Writing down some UX options for this for the design:

AndrewCopeland commented 4 years ago

@InbalZilberman Host annotation should use - instead of _. Example authn-gcp/service_account_email should be authn-gcp/service-account-email. This would stay consistent with authn-azure.

Can you have the same instance_name in different zones? Same applies with project_id?

    "compute_engine": {
      "instance_creation_timestamp": 1595766,
      "instance_id": "43405087601530",
      "instance_name": "vm-for-gcp",
      "project_id": "eng-serenity-2313",
      "project_number": 7161458341,
      "zone": "us-central1-a"
    }
sashaCher commented 4 years ago

project-id OR service-account-id OR service-account-email

@InbalZilberman What is the reason of OR? Are those parameters mutually exclusive?