diff --git a/docs/documentation/platform/pam/resources/aws-iam.mdx b/docs/documentation/platform/pam/resources/aws-iam.mdx index 2c1352c49..662d76b5e 100644 --- a/docs/documentation/platform/pam/resources/aws-iam.mdx +++ b/docs/documentation/platform/pam/resources/aws-iam.mdx @@ -14,13 +14,13 @@ Unlike database or SSH resources that require a Gateway for network connectivity sequenceDiagram participant User participant Infisical - participant PAM Role as PAM Role
(Your AWS Account) + participant Resource Role as Resource Role
(Your AWS Account) participant Target Role as Target Role
(Your AWS Account) participant Console as AWS Console User->>Infisical: Request AWS Console access - Infisical->>PAM Role: AssumeRole (with ExternalId) - PAM Role-->>Infisical: Temporary credentials + Infisical->>Resource Role: AssumeRole (with ExternalId) + Resource Role-->>Infisical: Temporary credentials Infisical->>Target Role: AssumeRole (role chaining) Target Role-->>Infisical: Session credentials Infisical->>Console: Generate federation URL @@ -31,174 +31,14 @@ sequenceDiagram ### Key Concepts -1. **PAM Role**: An IAM role in your AWS account that trusts Infisical. This is the "bridge" role that Infisical assumes first. +1. **Resource Role**: An IAM role in your AWS account that trusts Infisical. This is the "bridge" role that Infisical assumes first. -2. **Target Role**: The IAM role that end users will actually use in the AWS Console. The PAM Role assumes this role on behalf of the user. +2. **Target Role**: The IAM role that end users will actually use in the AWS Console. The Resource Role assumes this role on behalf of the user. -3. **Role Chaining**: Infisical uses AWS role chaining - it first assumes the PAM Role, then uses those credentials to assume the Target Role. This provides an additional layer of security and audit capability. +3. **Role Chaining**: Infisical uses AWS role chaining - it first assumes the Resource Role, then uses those credentials to assume the Target Role. This provides an additional layer of security and audit capability. 4. **External ID**: A unique identifier (your Infisical Project ID) used in the trust policy to prevent [confused deputy attacks](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html). -## Prerequisites - -Before configuring AWS Console access in Infisical PAM, you need to set up two IAM roles in your AWS account: - -1. **PAM Role** - Trusted by Infisical, can assume target roles -2. **Target Role(s)** - The actual roles users will use in the console - - - **No Gateway Required**: Unlike database or SSH resources, AWS Console access does not require an Infisical Gateway. Infisical communicates directly with AWS APIs. - - -## Step 1: Create the PAM Resource - -The PAM Resource represents the connection between Infisical and your AWS account. It contains the PAM Role that Infisical will assume. - -### 1.1 Create the PAM Role Permissions Policy - -First, create an IAM policy that allows the PAM Role to assume your target roles. We recommend using a wildcard pattern so you can add new target roles without updating this policy. - -```json -{ - "Version": "2012-10-17", - "Statement": [{ - "Effect": "Allow", - "Action": "sts:AssumeRole", - "Resource": "arn:aws:iam:::role/-*" - }] -} -``` - - - Choose a naming convention for your target roles (e.g., `pam-*`, `infisical-*`, or `privileged-*`). This allows you to add new accounts without modifying the PAM Role's permissions. - - -### 1.2 Create the PAM Role with Trust Policy - -Create an IAM role (e.g., `InfisicalPAMRole`) with: -- The permissions policy from step 1.1 attached -- The following trust policy: - -```json -{ - "Version": "2012-10-17", - "Statement": [{ - "Effect": "Allow", - "Principal": { - "AWS": "arn:aws:iam:::root" - }, - "Action": "sts:AssumeRole", - "Condition": { - "StringEquals": { - "sts:ExternalId": "" - } - } - }] -} -``` - - - **Security Best Practice**: Always use the External ID condition. This prevents confused deputy attacks where another Infisical customer could potentially trick Infisical into assuming your role. - - -**Infisical AWS Account IDs:** -| Region | Account ID | -|--------|------------| -| US | `381492033652` | -| EU | `345594589636` | - - - **For Dedicated Instances**: Your AWS account ID differs from the ones listed above. Please contact Infisical support to obtain your dedicated AWS account ID. - - -### 1.3 Create the Resource in Infisical - -1. Navigate to your PAM project and go to the **Resources** tab -2. Click **Add Resource** and select **AWS IAM** -3. Enter a name for the resource (e.g., `production-aws`) -4. Enter the **PAM Role ARN** - the ARN of the role you created in step 1.2 - -![Create AWS IAM Resource](/images/pam/resources/aws-iam/create-resource.png) - -Clicking **Create Resource** will validate that Infisical can assume the PAM Role. If the connection fails, verify: -- The trust policy has the correct Infisical AWS account ID -- The External ID matches your project ID -- The role ARN is correct - -## Step 2: Create PAM Accounts - -A PAM Account represents a specific Target Role that users can request access to. You can create multiple accounts per resource, each pointing to a different target role with different permission levels. - -### 2.1 Create the Target Role Trust Policy - -Each target role needs a trust policy that allows your PAM Role to assume it: - -```json -{ - "Version": "2012-10-17", - "Statement": [{ - "Effect": "Allow", - "Principal": { - "AWS": "arn:aws:iam:::role/InfisicalPAMRole" - }, - "Action": "sts:AssumeRole", - "Condition": { - "StringEquals": { - "sts:ExternalId": "" - } - } - }] -} -``` - - - **Tip**: If your target role name matches the wildcard pattern in your PAM Role's permissions policy (e.g., `pam-readonly`), you don't need to update the PAM Role's permissions. Just ensure the target role's trust policy is correct. - - -### 2.2 Create the Account in Infisical - -1. Navigate to the **Accounts** tab in your PAM project -2. Click **Add Account** and select the AWS IAM resource you created -3. Fill in the account details: - - - A friendly name for this account (e.g., `readonly`, `admin`, `developer`) - - - - Optional description of what this account is used for - - - - The ARN of the IAM role users will assume (e.g., `arn:aws:iam::123456789012:role/pam-readonly`) - - - - Session duration using human-readable format (e.g., `15m`, `30m`, `1h`). Minimum 15 minutes, maximum 1 hour. - - - Due to AWS role chaining limitations, the maximum session duration is **1 hour**, regardless of the target role's configured maximum session duration. - - - -![Create AWS IAM Account](/images/pam/resources/aws-iam/create-account.png) - -## Step 3: Access the AWS Console - -Once your resource and accounts are configured, users can request access through Infisical: - -1. Navigate to the **Accounts** tab -2. Find the AWS Console account you want to access -3. Click the **Access** button - -Infisical will: -1. Assume the PAM Role using your project's External ID -2. Assume the Target Role using role chaining -3. Generate a federated sign-in URL -4. Open the AWS Console in a new browser tab - -The user will be signed into the AWS Console with the permissions of the Target Role. - ## Session Behavior ### Session Duration @@ -229,16 +69,190 @@ arn:aws:sts::123456789012:assumed-role/pam-readonly/user@example.com This allows you to correlate Infisical PAM sessions with CloudTrail logs for complete audit visibility. -## Example: Multi-Environment Setup +## Prerequisites -A typical setup might include: +Before configuring AWS Console access in Infisical PAM, you need to set up two IAM roles in your AWS account: -**Resource**: `aws-production` (PAM Role in production account) -- **Account**: `readonly` → `arn:aws:iam::111111111111:role/pam-readonly` -- **Account**: `developer` → `arn:aws:iam::111111111111:role/pam-developer` -- **Account**: `admin` → `arn:aws:iam::111111111111:role/pam-admin` +1. **Resource Role** - Trusted by Infisical, can assume target roles +2. **Target Role(s)** - The actual roles users will use in the console -**Resource**: `aws-staging` (PAM Role in staging account) -- **Account**: `full-access` → `arn:aws:iam::222222222222:role/pam-full-access` + + **No Gateway Required**: Unlike database or SSH resources, AWS Console access does not require an Infisical Gateway. Infisical communicates directly with AWS APIs. + -Users can then be granted access to specific accounts based on their role and the approval workflows configured in Infisical. \ No newline at end of file +## Create the PAM Resource + +The PAM Resource represents the connection between Infisical and your AWS account. It contains the Resource Role that Infisical will assume. + + + + First, create an IAM policy that allows the Resource Role to assume your target roles. For simplicity, you can use a wildcard to allow assuming any role in your account: + + ```json + { + "Version": "2012-10-17", + "Statement": [{ + "Effect": "Allow", + "Action": "sts:AssumeRole", + "Resource": "arn:aws:iam:::role/*" + }] + } + ``` + + ![Create AWS IAM Resource](/images/pam/resources/aws-iam/resource-role-policy.png) + + + **For more granular control**: If you want to restrict which roles the Resource Role can assume, replace the wildcard (`/*`) with a more specific pattern. For example: + - `arn:aws:iam:::role/pam-*` to only allow roles with the `pam-` prefix + - `arn:aws:iam:::role/infisical-*` to only allow roles with the `infisical-` prefix + + This allows you to limit the blast radius of the Resource Role's permissions. + + + + + Create an IAM role (e.g., `InfisicalResourceRole`) with: + - The permissions policy from the previous step attached + - The following trust policy: + + ```json + { + "Version": "2012-10-17", + "Statement": [{ + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam:::root" + }, + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "sts:ExternalId": "" + } + } + }] + } + ``` + + ![Create AWS IAM Resource](/images/pam/resources/aws-iam/resource-role-trust-policy.png) + + ![Create AWS IAM Resource](/images/pam/resources/aws-iam/resource-role-attach-policy.png) + + + **Security Best Practice**: Always use the External ID condition. This prevents confused deputy attacks where another Infisical customer could potentially trick Infisical into assuming your role. + + + **Infisical AWS Account IDs:** + | Region | Account ID | + |--------|------------| + | US | `381492033652` | + | EU | `345594589636` | + + + **For Dedicated Instances**: Your AWS account ID differs from the ones listed above. Please contact Infisical support to obtain your dedicated AWS account ID. + + + + **For Self-Hosted Instances**: Use the AWS account ID where your Infisical instance is deployed. This is the account that hosts your Infisical infrastructure and will be assuming the Resource Role. + + + + + 1. Navigate to your PAM project and go to the **Resources** tab + 2. Click **Add Resource** and select **AWS IAM** + 3. Enter a name for the resource (e.g., `production-aws`) + 4. Enter the **Resource Role ARN** - the ARN of the role you created in the previous step + + ![Create AWS IAM Resource](/images/pam/resources/aws-iam/create-resource.png) + + Clicking **Create Resource** will validate that Infisical can assume the Resource Role. If the connection fails, verify: + - The trust policy has the correct Infisical AWS account ID + - The External ID matches your project ID + - The role ARN is correct + + + +## Create PAM Accounts + +A PAM Account represents a specific Target Role that users can request access to. You can create multiple accounts per resource, each pointing to a different target role with different permission levels. + + + + Each target role needs a trust policy that allows your Resource Role to assume it: + + ```json + { + "Version": "2012-10-17", + "Statement": [{ + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam:::role/InfisicalResourceRole" + }, + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "sts:ExternalId": "" + } + } + }] + } + ``` + + ![Create AWS IAM Resource](/images/pam/resources/aws-iam/target-role-trust-policy.png) + + + + 1. Navigate to the **Accounts** tab in your PAM project + 2. Click **Add Account** and select the AWS IAM resource you created + 3. Fill in the account details: + + ![Create AWS IAM Account](/images/pam/resources/aws-iam/create-account.png) + + + A friendly name for this account (e.g., `readonly`, `admin`, `developer`) + + + + Optional description of what this account is used for + + + + The ARN of the IAM role users will assume (e.g., `arn:aws:iam::123456789012:role/pam-readonly`) + + + + Session duration using human-readable format (e.g., `15m`, `30m`, `1h`). Minimum 15 minutes, maximum 1 hour. + + + Due to AWS role chaining limitations, the maximum session duration is **1 hour**, regardless of the target role's configured maximum session duration. + + + + + +## Access the AWS Console + +Once your resource and accounts are configured, users can request access through Infisical: + +![Create AWS IAM Resource](/images/pam/resources/aws-iam/access-account.png) + + + + Go to the **Accounts** tab in your PAM project. + + + + Find the AWS Console account you want to access. + + + + Click the **Access** button. + + Infisical will: + 1. Assume the Resource Role using your project's External ID + 2. Assume the Target Role using role chaining + 3. Generate a federated sign-in URL + 4. Open the AWS Console in a new browser tab + + The user will be signed into the AWS Console with the permissions of the Target Role. + + \ No newline at end of file diff --git a/docs/images/pam/resources/aws-iam/access-account.png b/docs/images/pam/resources/aws-iam/access-account.png new file mode 100644 index 000000000..6e6a57e1e Binary files /dev/null and b/docs/images/pam/resources/aws-iam/access-account.png differ diff --git a/docs/images/pam/resources/aws-iam/resource-role-attach-policy.png b/docs/images/pam/resources/aws-iam/resource-role-attach-policy.png new file mode 100644 index 000000000..39201c7cd Binary files /dev/null and b/docs/images/pam/resources/aws-iam/resource-role-attach-policy.png differ diff --git a/docs/images/pam/resources/aws-iam/resource-role-policy.png b/docs/images/pam/resources/aws-iam/resource-role-policy.png new file mode 100644 index 000000000..1c52aaebb Binary files /dev/null and b/docs/images/pam/resources/aws-iam/resource-role-policy.png differ diff --git a/docs/images/pam/resources/aws-iam/resource-role-trust-policy.png b/docs/images/pam/resources/aws-iam/resource-role-trust-policy.png new file mode 100644 index 000000000..7c018f985 Binary files /dev/null and b/docs/images/pam/resources/aws-iam/resource-role-trust-policy.png differ diff --git a/docs/images/pam/resources/aws-iam/target-role-trust-policy.png b/docs/images/pam/resources/aws-iam/target-role-trust-policy.png new file mode 100644 index 000000000..b91dd0030 Binary files /dev/null and b/docs/images/pam/resources/aws-iam/target-role-trust-policy.png differ diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/AwsIamAccountForm.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/AwsIamAccountForm.tsx index 779c21ba7..93ca6507f 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/AwsIamAccountForm.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/AwsIamAccountForm.tsx @@ -97,17 +97,17 @@ export const AwsIamAccountForm = ({ account, resourceId, resourceType, onSubmit enabled: !!resourceIdToFetch && !!resourceTypeToFetch }); - const pamRoleArn = + const resourceRoleArn = (resource?.resourceType === PamResourceType.AwsIam && (resource as TAwsIamResource).connectionDetails?.roleArn) || - "arn:aws:iam:::role/"; + "arn:aws:iam:::role/"; const targetRoleTrustPolicy = `{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { - "AWS": "${pamRoleArn}" + "AWS": "${resourceRoleArn}" }, "Action": "sts:AssumeRole", "Condition": { @@ -229,10 +229,9 @@ export const AwsIamAccountForm = ({ account, resourceId, resourceType, onSubmit

- The target role must have a trust policy that allows the PAM role (created in the - "Resources" tab) to assume it. If your target role name follows the - wildcard pattern you defined in the PAM role's permissions policy, no - additional changes are needed. + The target role must have a trust policy that allows the Resource Role (created in + the "Resources" tab) to assume it. Ensure the target role's trust + policy includes the Resource Role as a trusted principal.

@@ -247,12 +246,11 @@ export const AwsIamAccountForm = ({ account, resourceId, resourceType, onSubmit

- Note: The Principal role ARN shown above is from the PAM Resource + Note: The Principal role ARN shown above is from the Resource selected for this account. The External ID{" "} {projectId} is your - current project ID. If your target role name doesn't match the wildcard pattern - in your PAM Resource's role's permissions policy, you'll need to - update that policy to include this role's ARN. + current project ID. If you configured granular permissions in your Resource + Role's policy, ensure this target role's ARN is included.

diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountHeader.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountHeader.tsx index 0b84deb38..72120af8e 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountHeader.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountHeader.tsx @@ -1,5 +1,10 @@ +import { DocumentationLinkBadge } from "@app/components/v3"; import { PAM_RESOURCE_TYPE_MAP, PamResourceType } from "@app/hooks/api/pam"; +const PAM_ACCOUNT_DOCS_MAP: Partial> = { + [PamResourceType.AwsIam]: "aws-iam#create-pam-accounts" +}; + type Props = { resourceName: string; resourceType: PamResourceType; @@ -8,6 +13,7 @@ type Props = { export const PamAccountHeader = ({ resourceName, resourceType, onBack }: Props) => { const details = PAM_RESOURCE_TYPE_MAP[resourceType]; + const docsPath = PAM_ACCOUNT_DOCS_MAP[resourceType]; return (
@@ -17,7 +23,14 @@ export const PamAccountHeader = ({ resourceName, resourceType, onBack }: Props) className="h-12 w-12 rounded-md bg-bunker-500 p-2" />
-
{resourceName}
+
+ {resourceName} + {docsPath && ( + + )} +

{details.name} resource

{onBack && ( diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/AwsIamResourceForm.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/AwsIamResourceForm.tsx index ec97d0a6f..80652b3b5 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/AwsIamResourceForm.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/AwsIamResourceForm.tsx @@ -30,7 +30,7 @@ const AwsIamConnectionDetailsSchema = z.object({ roleArn: z .string() .trim() - .min(1, "PAM Role ARN is required") + .min(1, "Resource Role ARN is required") .refine((val) => arnRoleRegex.test(val), { message: "ARN must be in the format 'arn:aws:iam::123456789012:role/RoleName'" }) @@ -57,7 +57,7 @@ export const AwsIamResourceForm = ({ resource, onSubmit }: Props) => { "Statement": [{ "Effect": "Allow", "Action": "sts:AssumeRole", - "Resource": "arn:aws:iam:::role/-*" + "Resource": "arn:aws:iam:::role/*" }] }`; @@ -116,12 +116,15 @@ export const AwsIamResourceForm = ({ resource, onSubmit }: Props) => { control={control} render={({ field, fieldState: { error } }) => ( - + )} /> @@ -148,12 +151,12 @@ export const AwsIamResourceForm = ({ resource, onSubmit }: Props) => { Step 1: Create a permissions policy for assuming target roles

- This policy allows the PAM role to assume target roles. We recommend using a - wildcard pattern (e.g.,{" "} - pam-* or{" "} - privileged-*) so you - can add new accounts without updating this policy. Choose a prefix that fits your - naming conventions. + This policy allows the Resource Role to assume target roles. For simplicity, use a + wildcard to allow assuming any role in your account. For more granular control, + replace /* with a + specific pattern like{" "} + /pam-* or{" "} + /infisical-*.

@@ -165,12 +168,12 @@ export const AwsIamResourceForm = ({ resource, onSubmit }: Props) => {

- Step 2: Create the PAM role with a trust policy + Step 2: Create the Resource Role with a trust policy

Create an IAM role (e.g.,{" "} - InfisicalPAMRole) - with the permissions policy above and the following trust policy: + InfisicalResourceRole + ) with the permissions policy above and the following trust policy:

@@ -189,11 +192,8 @@ export const AwsIamResourceForm = ({ resource, onSubmit }: Props) => { {INFISICAL_AWS_ACCOUNT_EU} {" "} - for EU region. Replace{" "} - - <INFISICAL_AWS_ACCOUNT_ID> - {" "} - with the appropriate Infisical AWS account ID for your region. The External ID{" "} + for EU region. For dedicated instances, contact Infisical support. For self-hosted + instances, use your Infisical deployment's AWS account ID. The External ID{" "} {projectId} is your current project ID.

diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceHeader.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceHeader.tsx index 4b4fd34c4..c9b5e9274 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceHeader.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceHeader.tsx @@ -1,5 +1,10 @@ +import { DocumentationLinkBadge } from "@app/components/v3"; import { PAM_RESOURCE_TYPE_MAP, PamResourceType } from "@app/hooks/api/pam"; +const PAM_RESOURCE_DOCS_MAP: Partial> = { + [PamResourceType.AwsIam]: "aws-iam#create-the-pam-resource" +}; + type Props = { resourceType: PamResourceType; onBack?: () => void; @@ -7,6 +12,7 @@ type Props = { export const PamResourceHeader = ({ resourceType, onBack }: Props) => { const details = PAM_RESOURCE_TYPE_MAP[resourceType]; + const docsPath = PAM_RESOURCE_DOCS_MAP[resourceType]; return (
@@ -16,7 +22,14 @@ export const PamResourceHeader = ({ resourceType, onBack }: Props) => { className="h-12 w-12 rounded-md bg-bunker-500 p-2" />
-
{details.name}
+
+ {details.name} + {docsPath && ( + + )} +

Resource

{onBack && (