Skip to content

Secrets Manager integration

This document describes how Floecat uses AWS Secrets Manager, the required IAM permissions, and optional hardening with per-account role assumption.

Overview

Floecat stores secret payloads in AWS Secrets Manager using a key format:

accounts/<accountId>/<secretType>/<secretId>

Each secret is tagged with:

  • AccountId = the account id passed by Floecat

These tags support ABAC-style policies.

Connector AuthCredentials and storage-authority source credentials are written to Secrets Manager and removed from the corresponding persisted resource records. Connector responses mask sensitive auth fields, and storage-authority resolution only returns client-safe config plus any temporary credentials minted for a specific table/location match.

Connector secrets are never used for Iceberg REST client credential vending. Storage-authority secrets are the only credential source used for client credential vending.

Configuration

Optional role assumption:

  • floecat.secrets.aws.role-arn (optional)

If set, Floecat assumes this role per account operation and tags the STS session with AccountId=<accountId>. If unset, Floecat uses its default AWS credentials for all operations.

Set via system property:

-Dfloecat.secrets.aws.role-arn=arn:aws:iam::123456789012:role/floecat-secrets

Or via environment variable:

export FLOECAT_SECRETS_AWS_ROLE_ARN=arn:aws:iam::123456789012:role/floecat-secrets

Required IAM permissions (base)

The IAM identity Floecat runs under must be allowed to call Secrets Manager APIs. A minimal base policy looks like:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SecretsManagerBase",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:CreateSecret",
        "secretsmanager:GetSecretValue",
        "secretsmanager:PutSecretValue",
        "secretsmanager:DeleteSecret",
        "secretsmanager:TagResource"
      ],
      "Resource": "*"
    }
  ]
}

Quick start (AWS CLI validation)

Primary setup is granting the Floecat workload permissions to call Secrets Manager (see the IAM policy above). The commands here are a quick validation of access and the expected key format.

Set the identifiers and create a sample payload:

export ACCOUNT_ID=acct-123
export SECRET_TYPE=connectors   # or storage-authorities
export SECRET_ID=conn-001       # or a storage authority id such as sa-001
export SECRET_NAME="accounts/${ACCOUNT_ID}/${SECRET_TYPE}/${SECRET_ID}"

printf 'example-secret-payload' > payload.bin

Create a secret (binary payload):

aws secretsmanager create-secret \
  --name "$SECRET_NAME" \
  --secret-binary fileb://payload.bin \
  --tags Key=AccountId,Value="$ACCOUNT_ID"

Update the secret:

aws secretsmanager put-secret-value \
  --secret-id "$SECRET_NAME" \
  --secret-binary fileb://payload.bin

Read the secret:

aws secretsmanager get-secret-value \
  --secret-id "$SECRET_NAME" \
  --query 'SecretBinary' \
  --output text | base64 --decode

Delete the secret:

aws secretsmanager delete-secret \
  --secret-id "$SECRET_NAME" \
  --recovery-window-in-days 7

Optional hardening: per-account ABAC with role assumption

When floecat.secrets.aws.role-arn is set, Floecat will assume that role and attach an STS session tag AccountId=<accountId> for each operation. This allows you to enforce that secrets can only be accessed when the caller's AccountId tag matches the secret's AccountId tag.

Role trust policy

The role referenced by floecat.secrets.aws.role-arn must trust the Floecat base identity and allow session tagging:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAssumeRole",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/floecat-base"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Sid": "AllowSessionTags",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/floecat-base"
      },
      "Action": "sts:TagSession",
      "Condition": {
        "StringLike": {
          "aws:RequestTag/AccountId": "*"
        },
        "ForAllValues:StringEquals": {
          "aws:TagKeys": ["AccountId"]
        }
      }
    }
  ]
}

This follows the AWS STS session-tagging model: sts:TagSession is a permissions action in the trust policy, and tag constraints are expressed with condition keys such as aws:RequestTag/... and aws:TagKeys.

Role permissions policy

Attach a policy that enforces tag alignment:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SecretsByAccountTag",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:CreateSecret",
        "secretsmanager:GetSecretValue",
        "secretsmanager:PutSecretValue",
        "secretsmanager:DeleteSecret",
        "secretsmanager:TagResource"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "secretsmanager:ResourceTag/AccountId": "${aws:PrincipalTag/AccountId}"
        }
      }
    }
  ]
}

This prevents any caller from reading or writing secrets unless the secret is tagged with the same AccountId value as the session.