---
title: "AWS S3 Bucket"
description: "Configure AWS S3 bucket for deployment"
source: "Guardian Platform"
---
## Overview

The Guardian Platform requires AWS S3 buckets for blob storage.

**Required buckets:**

- **Governance artifacts bucket** – Stores governance-related documents and artifacts
- **Integrity store bucket** – Stores cryptographic proofs and audit trails

**This guide covers:**

- Creating S3 buckets with proper configuration (CLI or AWS Console)
- Setting up IAM users with S3 permissions
- Configuring the Helm chart for S3 storage

## Prerequisites

- AWS account with permissions to create S3 buckets and IAM users
- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) installed and configured (for CLI method)
- Two unique bucket names (S3 bucket names must be globally unique)

## Helm Configuration

Add the following to the `values.yaml` and `secrets.yaml` files. Placeholders will be filled in throughout the steps below.

`values.yaml`:

```yaml
governance-service:
  config:
    storageProvider: aws_s3
    awsS3Region: "<aws-region>" # Filled in after step 1
    awsS3BucketName: "<governance-bucket-name>" # Filled in after step 1

integrity-service:
  config:
    integrityAppBlobStoreType: aws_s3
    integrityAppBlobStoreAwsRegion: "<aws-region>" # Filled in after step 1
    integrityAppBlobStoreAwsBucket: "<integrity-bucket-name>" # Filled in after step 1
    integrityAppBlobStoreAwsFolder: rootstore
```

`secrets.yaml`:

```yaml
global:
  secrets:
    create: true
    storage:
      aws_s3:
        secretName: platform-aws-s3
        values:
          accessKeyId: "<access-key-id>" # Filled in after step 5
          secretAccessKey: "<secret-access-key>" # Filled in after step 5
```

## Quick Start (CLI Method - Recommended)

Create the buckets and an IAM user that can reach them with the AWS CLI, in five steps.

### 1. Create S3 Buckets

Choose an AWS region for the buckets (e.g. `us-east-1`, `eu-west-1`). All bucket commands and Helm values should use the same region.

Create the governance artifacts and integrity store buckets. Replace `<governance-bucket-name>` and `<integrity-bucket-name>` with globally unique names, and `<aws-region>` with the chosen region:

```bash
aws s3 mb s3://<governance-bucket-name> --region <aws-region>
aws s3 mb s3://<integrity-bucket-name> --region <aws-region>
```

Update `values.yaml` with the bucket names and region.

`values.yaml` -> governance-service.config:

```yaml
awsS3Region: "<aws-region>"
awsS3BucketName: "<governance-bucket-name>"
```

`values.yaml` -> integrity-service.config:

```yaml
integrityAppBlobStoreAwsRegion: "<aws-region>"
integrityAppBlobStoreAwsBucket: "<integrity-bucket-name>"
```

Optionally enable versioning on each bucket for data protection:

```bash
aws s3api put-bucket-versioning \
  --bucket <governance-bucket-name> \
  --versioning-configuration Status=Enabled
```

```bash
aws s3api put-bucket-versioning \
  --bucket <integrity-bucket-name> \
  --versioning-configuration Status=Enabled
```

### 2. Create IAM Policy

Create a policy document file named `s3-policy.json` with the following content, filling in the bucket names from step 1. The services read, write, and delete objects; `s3:ListBucket` lets a lookup of a missing object return not found instead of access denied:

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowObjectAccess",
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": [
        "arn:aws:s3:::<governance-bucket-name>/*",
        "arn:aws:s3:::<integrity-bucket-name>/*"
      ]
    },
    {
      "Sid": "AllowBucketListing",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": ["arn:aws:s3:::<governance-bucket-name>", "arn:aws:s3:::<integrity-bucket-name>"]
    }
  ]
}
```

Create the IAM policy:

```bash
aws iam create-policy \
  --policy-name governance-s3-access \
  --policy-document file://s3-policy.json \
  --description "Allow Guardian Platform to access S3 buckets"
```

Save the policy ARN from the output — it will look like `arn:aws:iam::123456789012:policy/governance-s3-access`.

### 3. Create IAM User

```bash
aws iam create-user --user-name guardian-platform
```

### 4. Attach Policy to User

To find the AWS account ID:

```bash
aws sts get-caller-identity --query Account --output text
```

Attach the policy. Replace `<account-id>` with the value from above:

```bash
aws iam attach-user-policy \
  --user-name guardian-platform \
  --policy-arn arn:aws:iam::<account-id>:policy/governance-s3-access
```

### 5. Create Access Key

```bash
aws iam create-access-key --user-name guardian-platform
```

Save both the `AccessKeyId` and `SecretAccessKey` from the output. The secret access key is only shown once and cannot be retrieved later.

The output will look like:

```json
{
  "AccessKey": {
    "UserName": "guardian-platform",
    "AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
    "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
    "Status": "Active"
  }
}
```

Update `secrets.yaml` with the credentials.

`secrets.yaml` -> global.secrets.storage.aws_s3.values:

```yaml
accessKeyId: "<access-key-id>"
secretAccessKey: "<secret-access-key>"
```

## Alternative: Web UI Setup

<details>
<summary>Click to expand AWS Console instructions</summary>

### Using the AWS Console

#### 1. Create S3 Buckets

- Navigate to S3 console
- Create two buckets: one for governance artifacts and another for the integrity store
- Note the bucket names and region

Update `values.yaml` with the bucket names and region.

`values.yaml` -> governance-service.config:

```yaml
awsS3Region: "<aws-region>"
awsS3BucketName: "<governance-bucket-name>"
```

`values.yaml` -> integrity-service.config:

```yaml
integrityAppBlobStoreAwsRegion: "<aws-region>"
integrityAppBlobStoreAwsBucket: "<integrity-bucket-name>"
```

#### 2. Create IAM User

- Navigate to IAM console
- Create a new IAM user
- Select "Attach policies directly"

#### 3. Create IAM Policy

- Select "Create Policy"
- Switch to the JSON editor and paste the policy from step 2 above, with both bucket names filled in

#### 4. Attach Policy and Create Access Key

- Create the policy and attach it to the IAM user
- Select the created IAM user, navigate to "Security Credentials" and create an access key
- Save the Access Key ID and Secret Access Key

Update `secrets.yaml` with the credentials.

`secrets.yaml` -> global.secrets.storage.aws_s3.values:

```yaml
accessKeyId: "<access-key-id>"
secretAccessKey: "<secret-access-key>"
```

</details>

## Verification

Test that the IAM user can access the buckets. Set the credentials from step 5:

```bash
export AWS_ACCESS_KEY_ID=<access-key-id>
export AWS_SECRET_ACCESS_KEY=<secret-access-key>
```

List objects in the governance artifacts bucket (should be empty initially):

```bash
aws s3 ls s3://<governance-bucket-name> --region <aws-region>
```

List objects in the integrity store bucket:

```bash
aws s3 ls s3://<integrity-bucket-name> --region <aws-region>
```

Clean up the temporary credentials:

```bash
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY
```

If the commands succeed without errors, the configuration is correct.

## IAM Roles for Service Accounts

On EKS, Governance Service and Integrity Service can use an IAM role through [IAM roles for service accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) instead of an access key. Attach the step 2 policy to a role that trusts both services' Kubernetes service accounts, then leave `global.secrets.storage.aws_s3.values` empty and set:

`values.yaml`:

```yaml
governance-service:
  serviceAccount:
    create: true
    annotations:
      eks.amazonaws.com/role-arn: "arn:aws:iam::<account-id>:role/<role-name>"
  config:
    awsS3UseIamRole: true

integrity-service:
  serviceAccount:
    create: true
    annotations:
      eks.amazonaws.com/role-arn: "arn:aws:iam::<account-id>:role/<role-name>"
  config:
    integrityAppBlobStoreAwsUseIamRole: true
```

With these set, the chart omits the access key variables and each service uses the AWS SDK's default credential chain.

## Security Best Practices

- **Least Privilege:** The IAM policy grants only object read, write, and delete plus bucket listing on the two buckets — avoid broadening to `s3:*` or account-wide permissions
- **Access Key Rotation:** Regularly rotate IAM access keys and update Kubernetes secrets
- **Block Public Access:** S3 blocks public access by default for new buckets — ensure this is not disabled
- **Enable Versioning:** Enable object versioning to protect against accidental deletion
- **Audit Logging:** Enable S3 server access logging or CloudTrail for access monitoring

## Official Documentation

- [AWS S3 CLI Reference](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/index.html)
- [AWS IAM CLI Reference](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/index.html)
- [S3 Bucket Best Practices](https://docs.aws.amazon.com/AmazonS3/latest/userguide/security-best-practices.html)
- [Helm Chart Examples](https://github.com/eqtylab/deployment/tree/main/charts/guardian-platform/examples)

## Related

- [Object Storage](./object-storage.mdx) — how S3 compares with the other storage providers
- [AWS KMS](./aws-kms.mdx) — the AWS key provider for DID signing keys
- [AWS RDS](./aws-rds.mdx) — the AWS managed database the platform can use
- [Backup and Restore](./backup-and-restore.mdx#object-storage) — versioning and replication for both buckets
- [Deployment Troubleshooting](./troubleshooting.mdx#attachments-fail) — first checks when attachments fail
- [Chart Values](./chart-values.mdx) — the full values and secrets files these settings go into