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

# AWS IAM roles

> Exactly which IAM roles Hilt asks you to create, what each one can do, and who needs what to deploy them.

Hilt never holds credentials in your accounts. You create IAM roles with CloudFormation, Hilt assumes them on demand, and deleting the stack revokes everything immediately.

There are only **two roles**, and one CloudFormation stack usually creates both.

| Role | Lives in | What it is for |
| :- | :- | :- |
| `HiltCloudConnectRole` | Every account with EC2 instances | See instances, install the agent, contain a host |
| `HiltCloudConnectOrgRole` | Your management account only | Read the list of accounts in your organization |

***

## Which stack do I deploy?

> [card] I have an AWS Organization
>
> Deploy **one** stack in your management account. It creates both roles and a StackSet that adds `HiltCloudConnectRole` to every current **and future** member account automatically.

> [card] I have one or a few accounts
>
> Deploy the per-account stack in each account. No organization, no StackSet, no management-account access needed.

Both paths start from the same place in the dashboard: **Settings → Integrations → AWS accounts**. Each button opens CloudFormation pre-filled — you sign in as yourself, review, and click Create. Hilt never receives your credentials.

> [!NOTE]
>
> **Organizations only, one-time:** StackSets need trusted access enabled. The CloudFormation console offers to turn it on while you create the stack, or run `aws cloudformation activate-organizations-access` once.

***

## What `HiltCloudConnectRole` can do

| Permission group | Why it exists |
| :- | :- |
| `ec2:Describe*` (instances, security groups, network interfaces, VPCs, tags, regions) | Build the instance inventory you see on **Collectors → Cloud** |
| `organizations:DescribeOrganization` | Recognise which organization the account belongs to |
| `ssm:SendCommand` on the AWS-owned `AWS-RunShellScript` document, plus command status reads | Run the agent installer. Pinned to that one document |
| `ec2:CreateSecurityGroup` / authorize / revoke / delete, **only on groups tagged `hilt:quarantine=true`** | Build the deny-all group used to contain a host |
| `ec2:ModifyNetworkInterfaceAttribute` | Swap a host's security groups to contain it, and swap them back |

### Optional: the connectivity permissions

Only present if you use PrivateLink to give agents a path to the collector:

| Permission group | Why it exists |
| :- | :- |
| `ec2:DescribeVpcEndpoints`, `DescribeVpcEndpointServices`, `DescribeSubnets` | Tell you which VPCs can reach the collector |
| `ec2:CreateVpcEndpoint`, `CreateTags`, and `DeleteVpcEndpoints` on **endpoints tagged `hilt:managed=true`** | Create the endpoint when you click **Connect** |
| `ec2:CreateSecurityGroup` and rules on **groups tagged `hilt:managed=true`** | The endpoint's own security group, allowing 443 from your VPC |
| `route53:AssociateVPCWithHostedZone` | Required by AWS whenever private DNS is enabled on an endpoint. **No hosted zone is created in your account** |
| `vpce:AllowMultiRegion` | Required by AWS only when your VPC is in a different region from Hilt's ingest service |

> [!NOTE]
>
> **Different regions are fine.** Since November 2024 AWS PrivateLink connects across regions: your VPC in one region can reach Hilt's ingest service in another, and the endpoint's network interfaces stay local to your VPC. Hilt enables your region on its service automatically the first time you connect from it - nothing for you to do.

### What it cannot do

It cannot touch IAM, open interactive SSM sessions, stop or terminate instances, read object storage, or modify any security group you own — quarantine and endpoint groups are tag-scoped, and Hilt creates those itself.

***

## What `HiltCloudConnectOrgRole` can do

Two read-only actions, and nothing else:

```
organizations:ListAccounts
organizations:DescribeOrganization
```

It exists only so Hilt can enumerate your accounts and keep up as you add new ones. It has no access to EC2, SSM, or any member account.

***

## How the trust works

Both roles pin three things at once. All three must match or the assume fails:

1. **Your Hilt deployment's account** — nobody else's
2. **The exact backend role ARN** in that account — not any role
3. **An ExternalId** unique to your deployment, shown in the dashboard

Every action Hilt takes arrives in **your** CloudTrail stamped with the Hilt user who triggered it, so a fleet install or a quarantine is always attributable to a person.

***

## Who needs what to deploy

**The per-account stack:** permission to create a CloudFormation stack and a named IAM role in that account.

**The organization stack** needs more, because it also creates a StackSet. An organization admin already has all of this; if you scope a role for it, this is the minimum:

```
cloudformation:CreateStack, UpdateStack, DeleteStack, DescribeStacks, DescribeStackEvents,
  DescribeStackResource(s), ListStackResources, ListStacks, GetTemplateSummary, ValidateTemplate,
  CreateChangeSet, DescribeChangeSet, ExecuteChangeSet, DeleteChangeSet
cloudformation:CreateStackSet, UpdateStackSet, DeleteStackSet, DescribeStackSet, ListStackSets,
  CreateStackInstances, DeleteStackInstances, ListStackInstances, DescribeStackInstance,
  DescribeStackSetOperation, ListStackSetOperations, ListStackSetOperationResults
cloudformation:ActivateOrganizationsAccess, DeactivateOrganizationsAccess,
  DescribeOrganizationsAccess

iam:CreateRole, DeleteRole, GetRole, TagRole, UntagRole, ListRoleTags,
  PutRolePolicy, DeleteRolePolicy, GetRolePolicy, ListRolePolicies, UpdateAssumeRolePolicy
  -> scoped to  role/HiltCloudConnectRole  and  role/HiltCloudConnectOrgRole

iam:CreateServiceLinkedRole, iam:GetRole
  -> on  role/aws-service-role/stacksets.cloudformation.amazonaws.com/*
     and role/aws-service-role/member.org.stacksets.cloudformation.amazonaws.com/*
     and role/AWSServiceRoleForCloudFormationStackSets*

organizations:DescribeOrganization, DescribeAccount, DescribeOrganizationalUnit, ListRoots,
  ListAccounts, ListAccountsForParent, ListOrganizationalUnitsForParent, ListParents,
  ListChildren, ListDelegatedAdministrators, EnableAWSServiceAccess,
  ListAWSServiceAccessForOrganization
```

> [!WARNING]
>
> The three service-linked-role paths are easy to miss. `ActivateOrganizationsAccess` checks whether the role exists *before* creating it, and when it does not yet exist AWS authorizes against the name **without** the `aws-service-role/` path — so granting only the pathed form fails with an `iam:GetRole` denial that does not explain itself.

This is only what **your** operator needs to run the stack once. It is not access granted to Hilt. Once the stack exists, the management account is not involved again.

***

## Updating an existing deployment

When Hilt adds a permission — the connectivity grants above, for example — accounts created from an older stack keep working, but the new feature stays greyed out until the stack is refreshed.

**With an organization**, this is one action, not one per account. Update the StackSet and CloudFormation pushes the new template to every member account:

```bash theme={null}
aws cloudformation update-stack-set \
  --stack-set-name hilt-cloud-connect \
  --template-url <the URL shown in the dashboard> \
  --capabilities CAPABILITY_NAMED_IAM \
  --parameters <same parameters as the original stack> \
  --operation-preferences FailureTolerancePercentage=100,MaxConcurrentPercentage=100
```

> [!WARNING]
>
> Pass `--operation-preferences` explicitly. The original rollout sets a failure tolerance in its template, but `update-stack-set` does **not** inherit it — it defaults to zero, so a single account that cannot update (one that already had the role from an earlier per-account stack, say) cancels the rollout for **every** account with `Cancelled since failure tolerance has exceeded`.

**Without an organization**, re-run the per-account stack in each account. Updating an existing stack in place is enough; you do not need to delete it first.

***

## Removing access

Delete the CloudFormation stack. The roles go with it and Hilt loses all access immediately — no support ticket, no waiting.

For an organization, delete the StackSet's stack instances first, then the stack that created it.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.