Set up keyless authentication

Learn how to implement keyless authentication for CI environments.

At Endor Labs, we believe that the most secure secret is one that doesn’t exist. That’s why in CI/CD environments we recommend using keyless authentication for machine authentication. Keyless Authentication uses OAuth for API authentication and removes the need to maintain and rotate an API key to Endor Labs.

Keyless Authentication is more secure and reduces the cost of secret rotation.

Configure keyless authentication using:

Enabling Keyless Authentication in Google Cloud

To enable Keyless Authentication in GCP you’ll first need permissions to create service accounts and assign these accounts roles to GCP.

The workflow to enable keyless authentication is:

  1. Create a service account with no permissions for federation.
  2. If you do not attach a service account to compute resources or use the default service account, we recommend creating a new service account for the compute resources. Create a service account to attach to compute resources and impersonate the federation service account.
  3. Create an authorization policy to allow the federation service account to authenticate to Endor Labs.
  4. Provision the compute resources with the appropriate permissions.
  5. Test Keyless authentication.

Creating GCP Service Accounts and Authorization Policies

To create your service accounts, first export your GCP project name as an environment variable:

export PROJECT=<insert-gcp-project>

Once you’ve set the environment variable you’ll create a service account that will be used to federate access to Endor Labs and will be provided permission to access the Endor Labs APIs:

Step 1: Create a federation service account called endorlabs-federation:

gcloud iam service-accounts create endorlabs-federation --description="Endor Labs Keyless Federation Service Account" --display-name="Endor Labs Federation Service Account"

We’ll also create a second service account, that will have access to impersonate the endorlabs-federation account. We’ll call this endorlabs-compute-service.

This is needed if you don’t already have service accounts for your compute resources. If you do, you need to modify the existing permissions to allow the existing service account to create a federation token.

Step 2: Create a keyless authentication service account to assign to compute resources called endorlabs-compute-service:

gcloud iam service-accounts create endorlabs-compute-service --description="Endor Labs Service account for keyless authentication" --display-name="Endor Labs Compute Instance SA"

Finally, we’ll assign endorlabs-compute-service permissions to impersonate the endorlabs-federation account to authenticate to Endor Labs through OIDC.

Step 3: Assign the serviceAccountOpenIdTokenCreator role to the endorlabs-compute-service service account:

gcloud projects add-iam-policy-binding $PROJECT --member="serviceAccount:endorlabs-compute-service@$PROJECT.iam.gserviceaccount.com" --role="roles/iam.serviceAccountOpenIdTokenCreator"

Once we’ve created the necessary account permissions we will create an authorization policy in Endor Labs to allow the account endorlabs-federation to your Endor Labs tenant:

Use the following command to create an authorization policy in Endor Labs.

Note: Make sure to replace with your Endor Labs tenant name and with your GCP project name in the following command.**

endorctl api create -r AuthorizationPolicy -d '{
    "tenant_meta": { "namespace": "<your-tenant>" },
    "meta": {
        "name": "Keyless Auth",
        "kind": "AuthorizationPolicy",
        "tags": ["gcp"]
     },
     "spec": {
        "clause": ["email=endorlabs-federation@<insert-your-project>.iam.gserviceaccount.com", "gcp"],
        "target_namespaces": ["<your-tenant>"],
        "propagate": true,
        "permissions": {
            "rules": {},
            "roles": [
                "SYSTEM_ROLE_CODE_SCANNER"
            ]
        },
    }
}'

You’ve now set up the foundation of keyless authentication. You’ll now need to provision your compute resources with the appropriate GCP scopes and service account.

See Provisioning and Testing Keyless Authentication for GKE workloads for instructions on setting up GKE for keyless authentication.

See Provisioning and Testing Keyless Authentication for GCP Virtual Machine Instances for instructions on setting up a virtual machine instance for keyless authentication.

Provisioning and Testing Keyless Authentication for GKE workloads

Prerequisites

The following pre-requisites are required to setup keyless authentication on GKE workloads:

Procedure:

  1. (Optional) Create a GKE cluster with workload identity enabled if you do not already have a GKE cluster
  2. Authenticate to the GKE cluster
  3. (Optional) Create a namespace for Endor Labs scans
  4. Create a Kubernetes service account to impersonate your GKE compute service account
  5. Bind your Kubernetes service account to your GCP compute service account
  6. Annotate your Kubernetes service account with your GCP service account to complete your binding
  7. Test a scanning workload using keyless authentication

Setting Up and Testing Keyless authentication in GKE

The following instructions require you to export the following environment variables to appropriately run:

  • The GCP Project as PROJECT
  • The GKE cluster as CLUSTER_NAME
export PROJECT=<Insert_GCP_Project>
export CLUSTER_NAME=<GKE_CLUSTER>

Optional Step 1: To create a GKE cluster with workload identity enabled if you do not already have a GKE cluster with workload identity enabled run the following command:

gcloud container clusters create keyless-test --workload-pool=endor-github.svc.id.goog --scopes https://www.googleapis.com/auth/cloud-platform

Step 2: To authenticate to your GKE cluster run the following command:

gcloud container clusters get-credentials $CLUSTER_NAME

Optional Step 3: To create a namespace for Endor Labs scans run the following command:

kubectl create namespace endorlabs

Step 4: To create a Kubernetes service account to impersonate your GKE compute service account run the following command:

kubectl create serviceaccount endorlabs-compute-service -n endorlabs

Step 5: To bind your Kubernetes service account to your GCP compute service account run the following command:

Note: Make sure to replace in the following command with your GCP project name.

gcloud iam service-accounts add-iam-policy-binding endorlabs-compute-service@$PROJECT.iam.gserviceaccount.com --role roles/iam.workloadIdentityUser --member "serviceAccount:<insert-your-project>.svc.id.goog[endorlabs/endorlabs-compute-service]"

Step 6: To annotate your Kubernetes service account with your GCP service account to complete your binding run the following command:

Note: If you have created a different service account name replace endorlabs-compute-service with the appropriate service account name.

kubectl annotate serviceaccount endorlabs-compute-service -n endorlabs iam.gke.io/gcp-service-account=endorlabs-compute-service@$PROJECT.iam.gserviceaccount.com

Step 7: Test scan your project with keyless authentication

You’ve set up and configured keyless authentication. Now you can run a test scan to ensure you can successfully scan projects using keyless authentication.

Provisioning and Testing Keyless Authentication for GCP Virtual Machine Instances

The following high-level procedure describes the required steps to use keyless authentication with a GCP virtual machine instance:

Procedure:

  1. Create a virtual machine instance with the appropriate scopes
  2. Download and install endorctl on the virtual machine instance
  3. Launch a test scan with keyless authentication

Setting up and Testing Keyless authentication on a GCP virtual machine instance

The following instructions require you to export the following environment variables to appropriately run:

  • The GCP Project as PROJECT
export PROJECT=<Insert_GCP_Project>

To successfully test keyless authentication first you’ll need to provision a compute resource with the service account endorlabs-compute-service@$PROJECT.iam.gserviceaccount.com and the scope https://www.googleapis.com/auth/cloud-platform:

Step 1: To create a virtual machine instance with the appropriate scopes run the following command:

gcloud compute instances create test-keyless --service-account endorlabs-compute-service@$PROJECT.iam.gserviceaccount.com --scopes https://www.googleapis.com/auth/cloud-platform

Step 2: To download and install endorctl on the virtual machine instance run the following series of commands:

First, SSH to the virtual machine instance you’ve created to test:

gcloud compute ssh --zone "us-west1-b" "test-keyless"  --project $PROJECT

Then download and install the latest version of endorctl. See our documentation for instructions on downloading the latest version

To scan with keyless authentication you must use the flag --gcp-service-account=endorlabs-federation@<insert-your-project>.iam.gserviceaccount.com for federated access to Endor Labs such as in the below example:

endorctl api list --gcp-service-account=endorlabs-federation@<insert-your-project>.iam.gserviceaccount.com -r Project -n <insert-your-tenant> --count

If this scan runs successfully you’ve tested and scanned a project with keyless authentication to Endor Labs.

Enabling Keyless Authentication in GitHub

To enable Keyless Authentication for GitHub Actions, you’ll need to perform the following steps:

  1. Ensure you are using the Endor Labs GitHub Action in your GitHub workflow.
  2. Edit your GitHub Action workflow to add permission settings for the GitHub id-token
  3. Create an authorization policy for GitHub Action OIDC
  4. Test that you can successfully scan a project using Github Action OIDC

Add a GitHub Action OIDC authorization policy

To ensure that the GitHub action OIDC identity can successfully login to Endor Labs you’ll need to create an authorization policy in Endor Labs.

To create an authorization policy:

  1. Under Manage go to Access Control
  2. Navigate to the “Auth Policy” tab
  3. Click on the “Add Auth Policy” button
  4. Select “GitHub Action OIDC” as your identity provider
  5. Select the permission for the GitHub Action. This permission should be “Code Scanner”
  6. For the claim use the key user and put in a matching value that maps to the organization of your GitHub repository.

Configuring your GitHub Action workflow

To configure your GitHub Action workflow with GitHub Action OIDC you can use the following example as a baseline.

The important items in this workflow are:

  1. The Usage of the Endor Labs GitHub action.
  2. Setting Job level permissions to allow writing to the GitHub id-token
  3. Enabling the usage of the GitHub Action token by settings enable_github_action_token to true
name: Example Scan of OWASP Java
on: workflow_dispatch
jobs:
  create_project_owasp:
    permissions:
      id-token: write # This is required for requesting the JWT
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v3
        with:
          repository: OWASP-Benchmark/BenchmarkJava
      - name: Setup Java
        uses: actions/setup-java@v3
        with:
          distribution: 'microsoft'
          java-version: '17'
      - name: Compile Package
        run: mvn clean install
      - name: Scan with Endor Labs
        uses: endorlabs/github-action@main # This workflow uses the Endor Labs GitHub action to scan.
        with:
          namespace: 'demo'
          scan_summary_output_type: 'json'
          pr: false
          scan_secrets: true
          scan_dependencies: true
          enable_github_action_token: true # This is required to have the GitHub Action use OIDC authentication

Now that you’ve successfully configured your GitHub action workflow file you can use this workflow file or one of your own designs to run a test scan using Keyless authentication for GitHub actions.

Enabling Keyless Authentication in AWS

To enable Keyless Authentication in AWS you’ll first need permissions to create or modify two roles and an instance profile with the appropriate roles configured

The two roles you will need are:

  1. An instance access role - The instance access role is assigned to the compute resource, which needs to access Endor Labs. Your instance access role may already exist and you must ensure this role provides the permissions to allow the role to assume the role of a dedicated federation role.
  2. A dedicated federation role - The dedicated federation role should have no permissions in AWS. Endor Labs will authorize requests that come from this role.

Procedure:

  1. Create or modify an existing Instance Profile that may be used to assign a role to your EC2 instance.
  2. Create or modify a role an instance access role, which enables services to assume a dedicated federation role.
  3. Assign this role to the Instance Profile
  4. Create a dedicated federation role to provide access to Endor Labs, which will be assumed by the instance access role
  5. Create an authorization policy in Endor Labs
  6. Test Keyless Authentication

Create or select an Instance Profile

An instance profile allows users to attach a single role to an EC2 instance. If you do not already have a pre-defined role or instance profile used by your EC2 instances you should create an instance profile for Endor Labs access.

To create an instance profile using the AWS CLI

aws iam create-instance-profile --instance-profile-name EndorLabsAccessProfile

Create or modify an instance access role

To successfully authenticate to Endor Labs you will need to assign an instance access role to the instance profile you created above.

The instance access role must at a minimum allow the compute resources that require access to perform the action sts:AssumeRole. If you already have a role you intend to assign to your instance profile, ensure that it has permissions to allow your compute resources to perform this action.

If you do not have an existing role you intend to use, create the role named endorlabs-instance-access-role using the instructions below.

First, add the following json to a file called endorlabs-instance-access-role.json

cat > endorlabs-instance-access-role.json <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "ec2.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
EOF

Use this file to create your instance access role using the following command:

aws iam create-role --role-name endorlabs-instance-access-role --assume-role-policy-document file://endorlabs-instance-access-role.json

Next, ensure that the instance access role is assigned to the instance profile using the following command:

aws iam add-role-to-instance-profile --instance-profile-name EndorLabsAccessProfile --role-name endorlabs-instance-access-role

Finally, create your EC2 instance and ensure that your instance profile is assigned to it.

Create a dedicated federation role

A dedicated federation role is leveraged to provide a least privileged role that enables access to Endor Labs. This role is designed to be assumed only by specific other roles and does not provide access to AWS resources.

To create your federation role you will need the name and AWS account number of the instance access role, which should look similar to the below policy json.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::$ACCOUNT:role/$ROLE_NAME"
            },
            "Action": "sts:AssumeRole"
        }
    ]
  }

First, get the account number of the role:

export ACCOUNT=$(aws sts get-caller-identity | jq -r '.Account')

Then define the name of the instance access role. For the following example, we will assume it is endorlabs-instance-access-role.

export ROLE_NAME=endorlabs-instance-access-role

Next, create the IAM policy document:

cat > endorlabs-federation-aws-role.json << EOF
{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Principal": {
              "AWS": "arn:aws:iam::${ACCOUNT}:role/${ROLE_NAME}"
          },
          "Action": "sts:AssumeRole"
      }
  ]
}
EOF

Next, apply the policy document as a role:

aws iam create-role --role-name endorlabs-federation --assume-role-policy-document file://endorlabs-federation-aws-role.json

Finally, fetch the ARN of the IAM role you’ve created using the following command and create an authorization policy for it in Endor Labs.

To fetch the ARN of the Endor Labs federation role use the following command:

aws iam list-roles | jq -r '.Roles[] | select(.Arn|contains("endorlabs-federation"))'.Arn

To add the authorization policy to Endor Labs:

  1. Login to Endor Labs as an administrator.
  2. Under Manage, navigate to Access Control > Auth Policy
  3. Click Add Auth Policy
  4. Under Identity Provider Select AWS role
  5. Provide the appropriate permissions for your authorization policy.
  6. Under claims use the Key User and the value of the ARN that you fetched in the previous command.
  7. Click Save Auth Policy to finalize your keyless authentication setup.

Testing Keyless Authentication with AWS

On the EC2 instance you’ve configured for keyless authentication, download and install the latest version of endorctl. See our documentation for instructions on downloading the latest version

To scan with keyless authentication you must use the flag --aws-role-arn=<insert-your-arn> for federated access to Endor Labs such as in the below example:

endorctl --aws-role-arn=<insert-your-arn> api list -r Project -n <insert-your-endorlabs-tenant> --page-size=1

You’ve set up and configured keyless authentication. Now you can run a test scan to ensure you can successfully scan projects using keyless authentication with AWS.