UNDERSTANDING AWS IAM AUTOMATION IN SWAMP
AWS IAM is a common place to start automating, and a risky one. A trust policy, an attached policy or an access key controls who can do what in an account. Mistakes in IAM tend to stay unnoticed until someone uses them. Swamp's IAM extensions put that work into behaviors whose definitions live in the repository and whose results are stored as data. This page covers how that mapping works and the decisions it leaves to the team.
One behavior type per IAM resource
The @swamp/aws/iam extension has one behavior type for each kind of IAM
resource. The types are role, user, group, managed-policy, role-policy,
user-policy, group-policy, instance-profile, oidcprovider, samlprovider,
server-certificate, service-linked-role and virtual-mfadevice. A behavior is one
configured instance of a type. Its global arguments hold the same properties you
would set in a CloudFormation AWS::IAM::Role or AWS::IAM::User resource, and
the names match, such as AssumeRolePolicyDocument, ManagedPolicyArns and
PermissionsBoundary. Teams already used to CloudFormation will recognise them.
Behaviors, Types, and Methods
explains the general relationship between a type and its behaviors.
Methods that change AWS and methods that read it
Every type has the same methods. create, update and delete change the
account. get, sync and, on most types, list only read it. Each run writes
the type's resource state, for example IAM Role resource state, into the
repository's data layer. This means a
behavior definition is not a desired-state file that Swamp keeps enforcing in
the background. It records what was asked for, and the resource state records
what AWS reported the last time a method ran. Running sync regularly keeps
that record current, which matters for IAM because people also change it through
the console and other tools.
Choosing who owns a policy
IAM lets you express the same permission in several ways, and the extension
supports all of them. A role, user or group can carry inline policies in its own
Policies argument and attach managed policies through ManagedPolicyArns. The
same attachments can also be separate behaviors: a role-policy, user-policy or
group-policy for an inline policy, or a managed-policy that lists its Roles,
Users and Groups.
Either approach works. The risk is using both for the same policy. If a role's
Policies and a separate role-policy behavior both describe the same inline
policy, each update overwrites the other's version, and which one wins depends
on which ran last. A useful rule is one owner per policy. Some teams keep
everything on the principal, so that one behavior shows everything a role can
do. Others make each policy its own behavior, so that a policy shared by several
roles is defined once. The separate policy types, along with oidcprovider,
samlprovider, service-linked-role and virtual-mfadevice, take a required name
argument because they are built for the
factory pattern,
where one definition creates many instances.
Credentials and secrets
Each type accepts accessKeyId, secretAccessKey and sessionToken. When they
are unset, the AWS environment variables and profile are used. That suits a
developer laptop with SSO, or a runner with an attached role. When the
credentials have to come from somewhere specific, wire the arguments with
${{ vault.get('<vault-name>', '<key>') }} so that the values are resolved at
run time and redacted from output, as shown in
Storing Secrets.
Auto-Refresh Cloud Credentials
covers keeping short-lived credentials current.
Some IAM arguments are secrets themselves. These include the password in a
user's LoginProfile, the PrivateKey of a server certificate and the
AddPrivateKey of a SAML provider. They belong in a vault for the same reason
the credentials do.
Access keys, which @swamp/aws/iam does not cover
CloudFormation-style resource types have no good way to represent an access key,
because the secret half exists only once, when the key is created.
@sntxrr/aws-access-key handles that
moment. It writes the new key straight into a named vault item and reads it back
to confirm the write. If the vault write fails, it rolls the key back, so a key
never exists in AWS without a copy in the vault. Deactivation and deletion are
separate methods, and delete will not remove an Active key. The result is a
rotation you can undo until the last step: if something still depends on the old
key, it fails while that key is only deactivated, and it can still be restored.
Rotate an IAM user access key into a Swamp vault
walks through the sequence.
Observing instead of managing
Not every account should be managed from a given repository. Security teams
often need to see IAM across dozens of accounts that other teams own.
@webframp/aws/iam scans a list of AWS profiles
and records roles, users, customer-managed policies and a cross-account trust
map. @jentz/aws-iam-role-audit checks
named integration roles against expected policies, trust principals and external
IDs. It also records a scan error for each account it could not assess, instead
of stopping the sweep. Both extensions only read IAM. The trade-off is clear.
They can never repair what they find, but they can run under read-only profiles
in accounts where write access would be inappropriate. Many teams combine the
two: @swamp/aws/iam for the accounts they own, and the read-only extensions
everywhere else.
Ordering and repeatability
IAM resources depend on each other. A role must exist before an instance profile
can hold it, before a role-policy can be embedded in it, and before a managed
policy can list it in Roles. Running these behaviors one at a time works, but
the order lives only in the operator's head. A workflow writes that order down
as steps. Because a failed run can be retried, it is worth designing the steps
so that running them twice does no harm.
The Workflow Execution Model
describes how steps are scheduled, and
Make Workflows Idempotent covers the
repeatable part.