> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/azfar-imtiaz/PayPulse-Cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# IAM roles

> IAM roles, policies, users, and groups in PayPulse Cloud.

All IAM resources are managed in the `iam` child module at `aws-infra-terraform/iam/`. The module is invoked from the root `main.tf` and receives table ARNs, secret ARNs, and configuration variables as inputs.

## Module structure

```
aws-infra-terraform/iam/
├── main.tf                              # Provider config
├── variables.tf                         # Module input variables
├── outputs.tf                           # Role ARN outputs consumed by root module
├── iam.tf                               # User, group, shared roles, and policies
├── iam_signup_lambda.tf
├── iam_login_lambda.tf
├── iam_delete_user_lambda.tf
├── iam_get_rental_invoice_lambda.tf
├── iam_get_rental_invoices_lambda.tf
├── iam_get_user_profile_lambda.tf
└── iam_gmail_store_tokens_lambda.tf
```

Each Lambda function that requires a custom IAM role has its own file in this directory. This keeps per-function permissions isolated and easy to audit.

## IAM user and group

### User: WallenstamTenant

```hcl theme={null}
resource "aws_iam_user" "wallenstam_user" {
  name = "WallenstamTenant"
}
```

This is the IAM user used for programmatic access to AWS resources from local development and Terraform.

### Group: Wallenstam

```hcl theme={null}
resource "aws_iam_group" "wallenstam_group" {
  name = "Wallenstam"
}
```

`WallenstamTenant` is a member of the `Wallenstam` group, which has the following AWS-managed policies attached:

| Policy                                 | Purpose                                         |
| -------------------------------------- | ----------------------------------------------- |
| `AmazonCognitoPowerUser`               | Manage Cognito identity pools                   |
| `AmazonDynamoDBFullAccess`             | Read/write all DynamoDB tables                  |
| `AmazonEC2ContainerRegistryFullAccess` | Push Docker images to ECR (for `parse_invoice`) |
| `AmazonS3FullAccess`                   | Manage S3 buckets and objects                   |
| `AmazonSNSFullAccess`                  | Publish to SNS topics                           |
| `AWSLambda_FullAccess`                 | Deploy and manage Lambda functions              |
| `CloudWatchEventsFullAccess`           | Manage EventBridge rules                        |
| `CloudWatchLogsFullAccess`             | Read and manage CloudWatch log groups           |
| `IAMFullAccess`                        | Manage IAM resources via Terraform              |
| `SecretsManagerReadWrite`              | Create and manage secrets                       |

Two additional inline policies are attached directly to the user (the group already has the maximum of 10 managed policies):

* **TerraformAutoScalingPermissions** — `application-autoscaling:Describe*` and `ListTagsForResource` for managing DynamoDB autoscaling
* **APIGatewayFullAccessPolicy** — `apigateway:*` for managing API Gateway resources

## Lambda execution roles

### Wallenstam-Lambda-Role

The primary shared execution role used by most Lambda functions. Attached managed policies:

* `AmazonDynamoDBFullAccess`
* `AmazonS3FullAccess`
* `AmazonSNSFullAccess`
* `CloudWatchLogsFullAccess`
* `SecretsManagerReadWrite`

### Per-function roles

Several Lambda functions have dedicated execution roles with narrowly scoped inline policies. These are defined in the per-function IAM files:

| Role name                         | File                                | Function              |
| --------------------------------- | ----------------------------------- | --------------------- |
| `Login-Lambda-Role`               | `iam_login_lambda.tf`               | `login_user`          |
| `Signup-Lambda-Role`              | `iam_signup_lambda.tf`              | `signup_user`         |
| `delete_user_lambda_role`         | `iam_delete_user_lambda.tf`         | `delete_user`         |
| `get_rental_invoices_lambda_role` | `iam_get_rental_invoices_lambda.tf` | `get_rental_invoices` |
| `get_rental_invoice_lambda_role`  | `iam_get_rental_invoice_lambda.tf`  | `get_rental_invoice`  |
| `get_user_profile_lambda_role`    | `iam_get_user_profile_lambda.tf`    | `get_user_profile`    |
| `gmail_store_tokens_lambda_role`  | `iam_gmail_store_tokens_lambda.tf`  | `gmail_store_tokens`  |

Each file follows the same pattern: an `aws_iam_role` with a Lambda trust policy, an `aws_iam_policy` with the minimum required permissions (typically DynamoDB table access and Secrets Manager read), and an `aws_iam_role_policy_attachment` binding the two.

Role ARNs are exported via `outputs.tf` and passed into the `lambdas` module by the root `main.tf`:

```hcl theme={null}
# In root main.tf
module "lambdas" {
  ...
  wallenstam_lambda_role_arn         = module.iam.wallenstam_lambda_role_arn
  signup_lambda_role_arn             = module.iam.signup_lambda_role_arn
  delete_user_lambda_role_arn        = module.iam.delete_user_lambda_role_arn
  get_invoices_lambda_role_arn       = module.iam.get_invoices_lambda_role_arn
  get_rental_invoice_lambda_role_arn = module.iam.get_rental_invoice_lambda_role_arn
  get_user_profile_lambda_role_arn   = module.iam.get_user_profile_lambda_role_arn
  gmail_store_tokens_lambda_role_arn = module.iam.gmail_store_tokens_lambda_role_arn
}
```

## App identity role

### WallenstamAppIdentityRole

This role is assumed by unauthenticated identities via the Cognito identity pool (`WallenstamAppIdentityPool`). It is used by the iOS app to register its APNs device token with SNS for push notifications.

```hcl theme={null}
resource "aws_iam_role" "wallenstam_app_identity_role" {
  name = "WallenstamAppIdentityRole"
  assume_role_policy = jsonencode({
    Statement = [{
      Effect    = "Allow",
      Principal = { Federated = "cognito-identity.amazonaws.com" },
      Action    = "sts:AssumeRoleWithWebIdentity",
      Condition = {
        "StringEquals" = {
          "cognito-identity.amazonaws.com:aud" = "eu-west-1:81322675-4a0a-4b9b-a406-0058e1e2d9f4"
        },
        "ForAnyValue:StringLike" = {
          "cognito-identity.amazonaws.com:amr" = "unauthenticated"
        }
      }
    }]
  })
}
```

Inline policies attached to this role:

| Policy                    | Permissions                                  |
| ------------------------- | -------------------------------------------- |
| `cognito-unauthenticated` | `cognito-identity:GetCredentialsForIdentity` |
| `wallenstam_sns_policy`   | `sns:CreatePlatformEndpoint`                 |

The `AmazonDynamoDBReadOnlyAccess` managed policy is also attached to allow the iOS app to read invoice data directly from DynamoDB if needed.

## Cognito identity pool

The `WallenstamAppIdentityPool` Cognito identity pool is defined in `cognito.tf`. It provides unauthenticated guest access for the iOS app, enabling it to call `sns:CreatePlatformEndpoint` to register for push notifications without requiring a full Cognito user pool login.

The identity pool is linked to `WallenstamAppIdentityRole` as its unauthenticated role.
