> ## Documentation Index
> Fetch the complete documentation index at: https://docs.porter.run/llms.txt
> Use this file to discover all available pages before exploring further.

# Secure cloud access

> Grant Porter applications secure access to AWS, GCP, and Azure resources using workload identity, IAM roles, and IRSA—no static credentials required.

Porter services can authenticate to your cloud accounts without you having to embed static access keys or service-principal secrets in environment variables. Instead, each pod assumes a cloud identity at runtime via your cloud provider's native workload-identity mechanism.

This page covers how to configure these identities for each supported cloud provider, and how to scope their permissions to follow the principle of least privilege.

***

## AWS

Porter uses [EKS Pod Identity](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html) to associate an IAM role with a service's pod. Your application code can then use the default AWS SDK credential chain (e.g. `DefaultAWSCredentialsProviderChain` in Java, `aws.config.LoadDefaultConfig` in Go, `boto3.Session()` in Python) and credentials will be resolved automatically — no access keys, no `sts:AssumeRole` calls in application code.

### How it works

When you attach an IAM role to a service, Porter creates an [EKS Pod Identity Association](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html) on your cluster that maps the service's Kubernetes service account to the IAM role you specify. At runtime, the EKS Pod Identity agent injects short-lived credentials for that role into the pod.

You are responsible for creating the IAM role and granting it the permissions it needs. Porter does not create the role or modify its permissions.

### Step 1 — Create the IAM role

In your AWS account, create a new IAM role with two things:

1. A **trust policy** that allows EKS Pod Identity to assume the role:

   ```json theme={null}
   {
     "Version": "2012-10-17",
     "Statement": [
       {
         "Effect": "Allow",
         "Principal": { "Service": "pods.eks.amazonaws.com" },
         "Action": ["sts:AssumeRole", "sts:TagSession"]
       }
     ]
   }
   ```

2. A **permissions policy** scoped to only the AWS APIs and resources your service needs.

We strongly recommend following the principle of least privilege: avoid wildcard actions and `Resource: "*"`, and create a dedicated role per service rather than sharing roles across workloads.

### Step 2 — Attach the role to your service

In the Porter dashboard, open the service you want to grant access to and scroll to the **IAM Role Connection** section. Toggle the connection on and enter the IAM role name or full ARN:

<img src="https://mintcdn.com/porter/Y8RLz4C78cfu_XJV/images/configure/aws-assume-role-example.webp?fit=max&auto=format&n=Y8RLz4C78cfu_XJV&q=85&s=685559197730e7f6dc833f551de15d30" alt="IAM Role Connection UI" width="614" height="469" data-path="images/configure/aws-assume-role-example.webp" />

On the next deploy, your pods can use the role immediately — no application restart logic required.

<Accordion title="Configure as code (porter.yaml)">
  If you manage your app config as code, you can declare the same connection in [`porter.yaml`](/applications/configuration-as-code/overview):

  ```yaml theme={null}
  services:
    - name: api
      # ...
      connections:
        - type: awsRole
          role: my-app-api-role
  ```

  See [Connections in porter.yaml](/applications/configuration-as-code/services/connections#aws-role-connection) for the full schema.
</Accordion>

***

## Azure

Porter uses [Azure Workload Identity](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview) to federate a service's Kubernetes service account with a User Assigned Managed Identity (UAMI) in your Azure subscription. Your application code can then use `DefaultAzureCredential` (or any credential type that supports workload identity) and Azure will issue tokens for the UAMI on the pod's behalf.

### How it works

When you attach a managed identity to a service, Porter creates a [federated identity credential](https://learn.microsoft.com/en-us/azure/active-directory/develop/workload-identity-federation) on the UAMI you specify. The credential trusts the AKS cluster's OIDC issuer to vouch for a specific Kubernetes service account. At runtime, the pod presents a projected OIDC token and Azure exchanges it for an access token scoped to the UAMI.

You are responsible for creating the UAMI and granting it role assignments. Porter does not create the UAMI or modify its permissions.

### Step 1 — Create a User Assigned Managed Identity

In the same Azure subscription as your AKS cluster, create a User Assigned Managed Identity and grant it the Azure RBAC role assignments needed to access the specific resources your service will call.

We strongly recommend following the principle of least privilege: scope role assignments to individual resources rather than resource groups or subscriptions, prefer narrow data-plane roles (e.g. `Storage Blob Data Reader`) over broad roles like `Contributor`, and create a dedicated UAMI per service.

You don't need to add any federated credentials yourself — Porter creates the one mapping your service's Kubernetes service account to this identity on the next deploy.

### Step 2 — Attach the identity to your service

In the Porter dashboard, open the service you want to grant access to and scroll to the **Azure Managed Identity Connection** section. Toggle the connection on and enter the managed identity name and resource group:

<img src="https://mintcdn.com/porter/Y8RLz4C78cfu_XJV/images/configure/azure-workload-identity-example.webp?fit=max&auto=format&n=Y8RLz4C78cfu_XJV&q=85&s=39fceb97f09dfed953db797f8da8ad7a" alt="Azure Managed Identity Connection UI" width="621" height="392" data-path="images/configure/azure-workload-identity-example.webp" />

On the next deploy, Porter creates the federated identity credential on the UAMI. From your application code, use `DefaultAzureCredential` from the Azure SDK and Azure will resolve credentials automatically — no client secrets, no certificates.

<Accordion title="Configure as code (porter.yaml)">
  If you manage your app config as code, you can declare the same connection in [`porter.yaml`](/applications/configuration-as-code/overview):

  ```yaml theme={null}
  services:
    - name: api
      # ...
      connections:
        - type: azureManagedIdentity
          identityName: my-app-api-identity
          resourceGroup: my-resource-group
  ```

  See [Connections in porter.yaml](/applications/configuration-as-code/services/connections#azure-managed-identity-connection) for the full schema.
</Accordion>

***

## GCP

Porter can bind a service to a GCP IAM service account in your project. Your application code can then use [Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials) (e.g. `google.auth.default()` in Python, `google.NewClient` in Go, `GoogleCredentials.getApplicationDefault()` in Java), and GCP will issue tokens for the bound IAM service account.

### How it works

When you attach a GCP IAM service account to a service, Porter configures the required IAM binding so the service can receive short-lived credentials scoped to the IAM service account.

You are responsible for creating the IAM service account and granting it the IAM roles it needs. Porter does not create the service account or modify its project-level permissions.

### Step 1 — Create a GCP IAM service account

In the same GCP project as your Porter infrastructure, create an IAM service account and grant it only the IAM roles needed to access the specific resources your service will call.

We strongly recommend following the principle of least privilege: prefer narrow predefined roles (e.g. `roles/storage.objectViewer` on a single bucket) over broad roles like `roles/editor`, scope role bindings to individual resources rather than the project, and create a dedicated service account per Porter service.

You don't need to add the service identity binding yourself — Porter adds it on the next deploy.

### Step 2 — Attach the service account to your service

In the Porter dashboard, open the service you want to grant access to and scroll to the **GCP Service Account Connection** section. Toggle the connection on and enter the fully-qualified service account email:

<img src="https://mintcdn.com/porter/Ct8PxZVCw_c9iwag/images/configure/gcp-service-account-connection.webp?fit=max&auto=format&n=Ct8PxZVCw_c9iwag&q=85&s=db36ad9bb9f688ec1f7976f72775c010" alt="GCP Service Account Connection UI" width="1236" height="518" data-path="images/configure/gcp-service-account-connection.webp" />

```
my-app@my-project.iam.gserviceaccount.com
```

On the next deploy, Porter adds the service identity binding on the IAM service account. From your application code, use the standard Google Cloud client libraries and credentials will be resolved automatically — no service account key files, no `GOOGLE_APPLICATION_CREDENTIALS` env var.

<Accordion title="Configure as code (porter.yaml)">
  If you manage your app config as code, you can declare the same connection in [`porter.yaml`](/applications/configuration-as-code/overview):

  ```yaml theme={null}
  services:
    - name: api
      # ...
      connections:
        - type: gcpServiceAccount
          serviceAccountEmail: my-app@my-project.iam.gserviceaccount.com
  ```

  See [Connections in porter.yaml](/applications/configuration-as-code/services/connections#gcp-service-account-connection) for the full schema.
</Accordion>

### Enabling Workload Identity on a node group

When you turn on Workload Identity for a node group, GKE deploys a metadata server on those nodes that intercepts calls to the GCE metadata endpoint. Once enabled, pods can no longer reach the node's default Compute Engine service account through that endpoint — they obtain Google credentials through a Workload Identity–bound Kubernetes service account instead.

<Warning>
  Enabling Workload Identity can interrupt workloads that rely on the node's default service account. If any pod on the node group authenticates to Google APIs using the default node service account (for example, through the GCE metadata endpoint or the default credential chain), it will lose access until it's reconfigured to use a Workload Identity–bound Kubernetes service account.
</Warning>

Before enabling it on a node group that already runs production traffic, confirm that none of its workloads depend on the default node service account. If you're not sure, create a new node group with Workload Identity enabled and [schedule your workloads](/cloud-accounts/node-groups#assigning-workloads-to-node-groups) on it to test before changing an existing node group.

***

## Related documentation

* [Configuration as code](/applications/configuration-as-code/overview) — Overview of managing Porter apps via `porter.yaml`
* [Connections in porter.yaml](/applications/configuration-as-code/services/connections) — Reference for all connection types, including the YAML schema
* [AWS EKS Pod Identity](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html) — AWS documentation
* [Azure Workload Identity](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview) — Azure documentation
* [Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials) — GCP documentation
