epack install collector aws
Adds to epack.yaml, resolves dependencies, downloads binary.
Run all configured collectors and build a pack:
epack collect
Runs all collectors in epack.yaml and outputs an evidence pack.
Or add manually to epack.yaml:
collectors:
aws:
source: https://github.com/locktivity/epack-collector-aws
Then run epack install to lock and sync.
The AWS collector gathers security posture metrics from AWS accounts. The
amount of detail it gathers is controlled by an optional level config knob
with three values: trust (default, pass/fail posture only), audit (adds
per-resource breakdowns), and internal (adds raw identifying detail for
breach investigation). See levels.md for the full contract.
This page lists the surfaces and their trust-level signals. Per-level field
breakdowns live in levels.md; the machine-readable shape lives
in schema/v1.0.0.json.
| Metric | Description |
|---|---|
credential_report_evaluated |
Whether the IAM credential report was collected. The user aggregates below are meaningful only when true |
credential_report_error_code |
Error code when the credential report could not be collected (e.g. CredentialReportTimeout) |
iam_users_present |
Whether at least one IAM user (excluding root) exists in the account |
mfa_enabled |
Percentage of IAM users with MFA enabled |
hardware_mfa_enabled |
Percentage of IAM users with hardware MFA (physical OTP devices or FIDO/U2F security keys) |
access_keys_rotated |
Percentage of access keys rotated within 90 days |
root_credential_state_evaluated |
Whether root credential state was read from the credential report or the account summary. The root credential flags below are meaningful only when true |
root_mfa_enabled |
Whether root MFA is active |
root_credentials_present |
Whether root has any password, access key, or signing certificate present |
root_password_present |
Whether root has a password present |
root_access_keys_exist |
Whether root has access keys (should be false) |
root_signing_certificates_present |
Whether root has signing certificates present |
root_access_protected |
Whether root MFA is active or no long-term root credentials are present |
root_organizations_features_evaluated |
Whether centralized root access features were read from IAM |
root_organization_id |
Organization ID returned by IAM when centralized root access features were read |
root_credentials_management_feature_enabled |
Whether IAM reported the RootCredentialsManagement centralized root access feature |
root_sessions_feature_enabled |
Whether IAM reported the RootSessions centralized root access feature |
root_organizations_features_error_code |
Error code when centralized root access features could not be read |
| Metric | Description |
|---|---|
bucket_listing_evaluated |
Whether the bucket listing was collected. The bucket aggregates below are meaningful only when true |
bucket_listing_error_code |
Error code when the bucket listing could not be collected |
account_public_access_block_evaluated |
Whether the account-level public access block settings were read |
bucket_count |
Total S3 buckets returned by ListBuckets |
public_access_blocked |
Percentage of buckets whose effective S3 Block Public Access settings block public access |
public_access_block_unknown_count |
Buckets whose effective S3 Block Public Access setting could not be fully evaluated |
default_encryption_enabled |
Percentage of evaluated buckets with default encryption |
default_encryption_evaluated_count |
Buckets whose default encryption setting was evaluated |
default_encryption_inferred_count |
Evaluated buckets counted from the documented AWS SSE-S3 baseline rather than a readable encryption rule |
default_encryption_unknown_count |
Buckets whose default encryption setting could not be evaluated |
versioning_enabled |
Percentage of buckets with versioning enabled |
logging_enabled |
Percentage of buckets with access logging |
account_public_access_block_enabled |
Whether account-level public access block is enabled |
| Metric | Description |
|---|---|
regions_evaluated_count |
Regions whose RDS listing succeeded; aggregates cover only these regions |
regions_failed |
Regions whose RDS listing failed. Aggregates are meaningful only when absent |
database_count |
Instances plus clusters across evaluated regions |
encrypted_at_rest |
Percentage of instances/clusters with encryption |
publicly_accessible |
Percentage publicly accessible (should be 0%) |
deletion_protection |
Percentage with deletion protection enabled |
backup_retention_adequate |
Percentage with backup retention >= 7 days |
multi_az_enabled |
Percentage with Multi-AZ deployment |
| Metric | Description |
|---|---|
regions_evaluated_count |
Regions whose network listing succeeded; exposure aggregates cover only these regions |
regions_failed |
Regions whose network listing failed. Exposure aggregates are meaningful only when absent, since partial coverage can only understate exposure |
open_to_world_ssh |
Percentage of security groups allowing SSH from 0.0.0.0/0 |
open_to_world_rdp |
Percentage allowing RDP from 0.0.0.0/0 |
vpcs[].flow_logs_enabled |
Internal-level per-VPC flow log status |
vpcs[].flow_logs_evaluated |
Whether internal-level flow log status was evaluated for the VPC |
vpcs[].flow_logs_error_code |
Error code when internal-level flow log status could not be read |
| Service | Metrics |
|---|---|
| CloudTrail | Trail-listing evaluated marker and error code, enabled, multi-region, organization trail coverage, trail-status evaluated / inferred / unknown counts |
| AWS Config | Enabled, recorder running |
| GuardDuty | Enabled, unremediated high/critical findings >48h |
| Security Hub | Enabled, CIS AWS Foundations Benchmark level 1/2/unknown-level compliance |
| Inspector | Status evaluated marker and error code, enabled, unpatched server % |
For CIS level splits, the collector uses Security Hub finding related_requirements level tags and aggregates to one status per control (FAILED > WARNING > PASSED > NOT_AVAILABLE).
Findings without explicit level tags are reported in an explicit unknown-level bucket.
Interpretation guide:
- security_hub.enabled=true means Security Hub is available in the account/region.
- level_1 and level_2 values are only populated when findings include explicit level tags.
- unknown_level captures CIS controls where Security Hub did not provide a level tag.
| Metric | Description |
|---|---|
enabled |
Whether an IdC instance exists in the primary region |
user_count |
Users in the connected identity store |
group_count |
Groups in the connected identity store |
permission_set_count |
Permission sets provisioned on the instance |
| Metric | Description |
|---|---|
function_count |
Total Lambda functions across regions |
deprecated_runtime_count |
Functions on AWS-deprecated runtimes (Node ≤16, Python ≤3.8, Ruby ≤2.7, Java 8, Go 1.x, .NET Core ≤6) |
| Metric | Description |
|---|---|
instance_count |
Running instances across regions |
imdsv2_required_count |
Instances enforcing IMDSv2 (HttpTokens=required) |
public_ip_count |
Instances with a public IP |
default_vpc_count |
Instances in the default VPC (anti-pattern) |
instances_with_unencrypted_volume_count |
Instances with at least one unencrypted attached EBS volume |
| Metric | Description |
|---|---|
log_group_count |
Log groups across regions |
log_groups_without_retention_count |
Groups with no retention policy (logs accumulate forever) |
log_groups_without_customer_kms_count |
Groups using AWS-managed (vs customer-managed) KMS |
Scoped to CUSTOMER-managed keys only; AWS-managed keys offer no posture lever.
| Metric | Description |
|---|---|
customer_managed_key_count |
Customer-managed keys across regions |
cmks_with_rotation_disabled_count |
Symmetric CMKs without automatic key rotation |
cmks_pending_deletion_count |
Keys scheduled for deletion |
Secret VALUES are NEVER collected — only metadata. Value-reading APIs are forbidden in collector source by build-time lint.
| Metric | Description |
|---|---|
secret_count |
Secrets across regions |
secrets_without_rotation_count |
Secrets without auto-rotation configured |
secrets_without_customer_kms_count |
Secrets using AWS-managed (vs customer-managed) KMS |
secrets_pending_deletion_count |
Secrets scheduled for deletion |
Parameter VALUES are NEVER collected — only metadata. Value-reading APIs are forbidden in collector source by build-time lint.
| Metric | Description |
|---|---|
parameter_count |
Parameters across regions |
secure_string_count |
SecureString-type parameters (the encrypted, sensitive ones) |
secure_strings_without_customer_kms_count |
SecureStrings using alias/aws/ssm (vs a customer-managed key) |
go test ./...AWS_E2E_RUN=true go test -tags=e2e -v ./internal/collector/...The collector automatically handles AWS's regional vs global services:
Metrics from regional services are aggregated across all regions.
Configure multiple accounts to collect from all AWS accounts in your organization:
collectors:
- name: aws
config:
accounts:
- role_arn: "arn:aws:iam::111111111111:role/EpackCollectorRole"
label: "production"
- role_arn: "arn:aws:iam::222222222222:role/EpackCollectorRole"
label: "staging"
The optional label is operator-supplied and rides each account's output as
account_label, including failed-account records.
Each account's posture is collected independently and included in the output.
An account that fails entirely is recorded under failed_accounts (with the
account ID parsed from its role ARN and the upstream error code) instead of
silently disappearing, and the normalized artifact carries a matching stub
entry plus an accounts_expected count.
The AWS collector supports multiple authentication methods. The auth_mode option controls how the collector assumes IAM roles:
oidc - Uses GitHub Actions OIDC to assume roles via AssumeRoleWithWebIdentity (recommended for GitHub Actions)assume_role - Uses standard AssumeRole with optional external_id (default for backward compatibility)When running in GitHub Actions, OIDC provides secure, credential-free authentication. The collector obtains a JWT token from GitHub and exchanges it for temporary AWS credentials.
Trust Policy (OIDC):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:your-org/your-repo:*"
}
}
}
]
}
Configuration:
collectors:
aws:
source: "locktivity/epack-collector-aws@^0.1.0"
config:
auth_mode: "oidc"
role_arn: "arn:aws:iam::123456789012:role/EpackCollectorRole"
secrets:
- ACTIONS_ID_TOKEN_REQUEST_URL
- ACTIONS_ID_TOKEN_REQUEST_TOKEN
GitHub Actions Workflow:
permissions:
id-token: write # Required for OIDC
contents: read
For environments without OIDC support, use standard AssumeRole with bootstrap credentials.
Trust Policy (AssumeRole):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::COLLECTOR_ACCOUNT:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "your-external-id"
}
}
}
]
}
Configuration:
collectors:
aws:
source: "locktivity/epack-collector-aws@^0.1.0"
config:
auth_mode: "assume_role"
role_arn: "arn:aws:iam::123456789012:role/EpackCollectorRole"
external_id: "your-external-id"
If no role_arn is specified, the collector uses the AWS SDK's default credential chain:
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)~/.aws/credentials)collectors:
aws:
source: "locktivity/epack-collector-aws@^0.1.0"
config:
regions:
- us-east-1
The collector needs read-only AWS permissions in each target account. The minimum set depends on the level config (see levels.md). Levels are cumulative: audit needs the trust set plus more; internal needs the audit set plus more.
All actions are List, Describe, or Get. Value-reading APIs (secretsmanager:GetSecretValue, ssm:GetParameter, etc.) are intentionally absent and are forbidden in collector source by a build-time lint.
If a surface is missing its required permissions, the collector emits a per-surface AccessDenied diagnostic warning and continues; it does not fail the whole run.
iam:ListOrganizationsFeatures only evaluates centralized root access from the AWS Organizations management account or an IAM delegated administrator account. Member-account roles record the AWS error code in the evidence pack instead of inferring the organization-level state.
The minimum policy. Required for every collection level.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sts:GetCallerIdentity",
"iam:GenerateCredentialReport",
"iam:GetAccountPasswordPolicy",
"iam:GetAccountSummary",
"iam:GetCredentialReport",
"iam:ListAccountAliases",
"iam:ListOrganizationsFeatures",
"iam:ListMFADevices",
"iam:ListRoles",
"s3:GetAccountPublicAccessBlock",
"s3:GetBucketLocation",
"s3:GetBucketLogging",
"s3:GetBucketPolicy",
"s3:GetBucketObjectLockConfiguration",
"s3:GetBucketPublicAccessBlock",
"s3:GetBucketVersioning",
"s3:GetEncryptionConfiguration",
"s3:GetLifecycleConfiguration",
"s3:ListAllMyBuckets",
"ec2:DescribeImages",
"ec2:DescribeInstances",
"ec2:DescribeRegions",
"ec2:DescribeSecurityGroups",
"ec2:DescribeSnapshots",
"ec2:DescribeVolumes",
"ec2:DescribeVpcs",
"cloudfront:ListDistributions",
"cloudwatch:DescribeAlarms",
"elasticloadbalancing:DescribeListeners",
"elasticloadbalancing:DescribeLoadBalancers",
"sns:ListSubscriptionsByTopic",
"wafv2:ListWebACLs",
"wafv2:GetWebACL",
"wafv2:ListResourcesForWebACL",
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribePolicies",
"application-autoscaling:DescribeScalableTargets",
"application-autoscaling:DescribeScalingPolicies",
"ecs:DescribeServices",
"ecs:ListClusters",
"ecs:ListServices",
"elasticloadbalancing:DescribeTargetGroups",
"ses:GetConfigurationSet",
"ses:GetEmailIdentity",
"ses:ListConfigurationSets",
"ses:ListEmailIdentities",
"rds:DescribeDBClusters",
"rds:DescribeDBParameters",
"rds:DescribeEventSubscriptions",
"rds:DescribeDBInstances",
"cloudtrail:DescribeTrails",
"cloudtrail:GetTrailStatus",
"config:DescribeConfigurationRecorders",
"config:DescribeConfigurationRecorderStatus",
"guardduty:GetDetector",
"guardduty:ListDetectors",
"guardduty:ListFindings",
"securityhub:DescribeHub",
"securityhub:GetEnabledStandards",
"securityhub:GetFindings",
"securityhub:ListEnabledProductsForImport",
"access-analyzer:ListAnalyzers",
"access-analyzer:ListFindings",
"sso:ListInstances",
"sso:ListPermissionSets",
"identitystore:ListGroups",
"identitystore:ListUsers",
"lambda:ListFunctions",
"logs:DescribeLogGroups",
"kms:DescribeKey",
"kms:GetKeyRotationStatus",
"kms:ListKeys",
"secretsmanager:ListSecrets",
"ssm:DescribeParameters"
],
"Resource": "*"
}
]
}
Add these actions to the trust-level policy above. They surface the Identity Center access model (permission sets, the user and group roster, membership and account-assignment edges), per-function Lambda configuration, KMS alias enrichment, web ACL logging state, and the organization-membership classification of cross-account role trust.
[
"sso:DescribePermissionSet",
"sso:ListAccountsForProvisionedPermissionSet",
"sso:ListManagedPoliciesInPermissionSet",
"sso:GetInlinePolicyForPermissionSet",
"sso:ListAccountAssignments",
"identitystore:ListGroupMemberships",
"organizations:ListAccounts",
"lambda:GetPolicy",
"lambda:ListFunctionUrlConfigs",
"kms:ListAliases",
"wafv2:GetLoggingConfiguration"
]
wafv2:GetLoggingConfiguration is best effort: without it, per-ACL rows report logging_evaluated: false rather than failing the region.
organizations:ListAccounts is optional and best effort: it succeeds only from the Organizations management account or a delegated administrator. Without it, per-role external_trust_in_org determinations are absent rather than guessed, and the run continues.
Add these actions on top of the audit-level set. They surface per-rule Config compliance, GuardDuty finding payloads, per-bucket S3 ACL configuration, and per-VPC flow log status.
[
"config:DescribeConfigRules",
"config:DescribeComplianceByConfigRule",
"config:DescribeConfigRuleEvaluationStatus",
"guardduty:GetFindings",
"ec2:DescribeFlowLogs",
"s3:GetBucketAcl"
]
For organizations with multiple AWS accounts:
Each target account needs a role trusting the GitHub OIDC provider:
collectors:
aws:
source: "locktivity/epack-collector-aws@^0.1.0"
config:
auth_mode: "oidc"
accounts:
- role_arn: "arn:aws:iam::111111111111:role/EpackCollectorRole"
- role_arn: "arn:aws:iam::222222222222:role/EpackCollectorRole"
- role_arn: "arn:aws:iam::333333333333:role/EpackCollectorRole"
regions:
- us-east-1
- us-west-2
- eu-west-1
secrets:
- ACTIONS_ID_TOKEN_REQUEST_URL
- ACTIONS_ID_TOKEN_REQUEST_TOKEN
Each target account needs a role trusting the bootstrap account:
collectors:
aws:
source: "locktivity/epack-collector-aws@^0.1.0"
config:
auth_mode: "assume_role"
accounts:
- role_arn: "arn:aws:iam::111111111111:role/EpackCollectorRole"
external_id: "prod-123"
- role_arn: "arn:aws:iam::222222222222:role/EpackCollectorRole"
external_id: "staging-456"
- role_arn: "arn:aws:iam::333333333333:role/EpackCollectorRole"
external_id: "dev-789"
regions:
- us-east-1
- us-west-2
- eu-west-1
Note:
external_idis ignored in OIDC mode. The OIDC token claims provide equivalent security through repository/branch constraints in the trust policy.
By default, the collector discovers all enabled regions in the account and scans up to five of them concurrently. AWS rate limits are per region, so concurrent regions do not compete for API quotas. To limit to specific regions:
collectors:
aws:
source: "locktivity/epack-collector-aws@^0.1.0"
config:
regions:
- us-east-1
- us-west-2
The collector automatically retries generating the credential report. If it times out after 10 attempts, check IAM permissions for iam:GenerateCredentialReport.
Some services (like GuardDuty) may not be available in all regions. The collector handles this gracefully and continues with available services.
The AWS SDK automatically handles rate limiting with exponential backoff. For large accounts with many resources, collection may take several minutes.
Collect from the current AWS account using default credentials:
collectors:
aws:
source: "locktivity/epack-collector-aws@^0.1.0"
config: {}
collectors:
aws:
source: "locktivity/epack-collector-aws@^0.1.0"
config:
auth_mode: "oidc"
role_arn: "arn:aws:iam::123456789012:role/EpackCollectorRole"
secrets:
- ACTIONS_ID_TOKEN_REQUEST_URL
- ACTIONS_ID_TOKEN_REQUEST_TOKEN
collectors:
aws:
source: "locktivity/epack-collector-aws@^0.1.0"
config:
auth_mode: "assume_role"
role_arn: "arn:aws:iam::123456789012:role/EpackCollectorRole"
external_id: "epack-collection-abc123"
collectors:
aws:
source: "locktivity/epack-collector-aws@^0.1.0"
config:
auth_mode: "oidc"
accounts:
- role_arn: "arn:aws:iam::111111111111:role/EpackCollectorRole"
- role_arn: "arn:aws:iam::222222222222:role/EpackCollectorRole"
- role_arn: "arn:aws:iam::333333333333:role/EpackCollectorRole"
secrets:
- ACTIONS_ID_TOKEN_REQUEST_URL
- ACTIONS_ID_TOKEN_REQUEST_TOKEN
collectors:
aws:
source: "locktivity/epack-collector-aws@^0.1.0"
config:
auth_mode: "assume_role"
accounts:
- role_arn: "arn:aws:iam::111111111111:role/EpackCollectorRole"
external_id: "prod"
label: "production"
- role_arn: "arn:aws:iam::222222222222:role/EpackCollectorRole"
external_id: "staging"
label: "staging"
- role_arn: "arn:aws:iam::333333333333:role/EpackCollectorRole"
external_id: "dev"
label: "development"
label is optional, operator-supplied free text (e.g. production, staging,
management). It is carried verbatim onto the account's entries in both
artifacts as account_label (and onto a failed account's failed_accounts
record), so downstream consumers can segment accounts without an external
mapping.
Limit collection to specific regions:
collectors:
aws:
source: "locktivity/epack-collector-aws@^0.1.0"
config:
role_arn: "arn:aws:iam::123456789012:role/EpackCollectorRole"
regions:
- us-east-1
- us-west-2
- eu-west-1
Metrics use percentages (0-100), booleans, and counts where appropriate.
{
"schema_version": "1.0.0",
"collected_at": "2024-01-15T10:30:00Z",
"accounts": [
{
"account_id": "123456789012",
"account_alias": "production",
"regions": ["us-east-1", "us-west-2"],
"iam": {
"credential_report_evaluated": true,
"iam_users_present": true,
"mfa_enabled": 95,
"hardware_mfa_enabled": 0,
"access_keys_rotated": 80,
"root_credential_state_evaluated": true,
"root_mfa_enabled": true,
"root_credentials_present": true,
"root_password_present": true,
"root_access_keys_exist": false,
"root_signing_certificates_present": false,
"root_access_protected": true,
"root_organizations_features_evaluated": true,
"root_organization_id": "o-abc1234567",
"root_credentials_management_feature_enabled": true,
"root_sessions_feature_enabled": true
},
"s3": {
"bucket_listing_evaluated": true,
"account_public_access_block_evaluated": true,
"bucket_count": 20,
"public_access_blocked": 100,
"public_access_block_unknown_count": 0,
"default_encryption_enabled": 95,
"default_encryption_evaluated_count": 20,
"default_encryption_inferred_count": 0,
"default_encryption_unknown_count": 0,
"versioning_enabled": 60,
"logging_enabled": 40,
"account_public_access_block_enabled": true
},
"rds": {
"regions_evaluated_count": 2,
"database_count": 6,
"encrypted_at_rest": 100,
"publicly_accessible": 0,
"deletion_protection": 90,
"backup_retention_adequate": 100,
"multi_az_enabled": 80
},
"network": {
"regions_evaluated_count": 2,
"open_to_world_ssh": 2,
"open_to_world_rdp": 0
},
"account_security": {
"cloudtrail": {
"trail_listing_evaluated": true,
"enabled": true,
"multi_region_enabled": true,
"organization_trail_enabled": true,
"trail_status_evaluated_count": 1,
"trail_status_inferred_count": 0,
"trail_status_unknown_count": 0
},
"config": {
"enabled": true,
"recorder_running": true
},
"guardduty": {
"enabled": true,
"unremediated_findings_over_48h": 1
},
"security_hub": {
"enabled": true,
"cis_aws_foundations_benchmark_level_1": {
"enabled": true,
"compliance_percent": 88,
"compliance_state": "WARNING",
"passed_controls": 44,
"failed_controls": 3,
"warning_controls": 3,
"not_available_controls": 1
},
"cis_aws_foundations_benchmark_level_2": {
"enabled": true,
"compliance_percent": 82,
"compliance_state": "FAILED",
"passed_controls": 55,
"failed_controls": 8,
"warning_controls": 4,
"not_available_controls": 2
},
"cis_aws_foundations_benchmark_unknown_level": {
"enabled": true,
"compliance_percent": 90,
"compliance_state": "FAILED",
"passed_controls": 9,
"failed_controls": 1,
"warning_controls": 0,
"not_available_controls": 0
}
},
"inspector": {
"status_evaluated": true,
"enabled": true,
"unpatched_server_percent": 25
}
}
}
]
}
Using OIDC, the collector obtains credentials directly from GitHub without needing aws-actions/configure-aws-credentials:
name: Security Posture Collection
on:
schedule:
- cron: '0 6 * * *' # Daily at 6 AM UTC
workflow_dispatch:
jobs:
collect:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC token
contents: read
steps:
- name: Install epack
run: |
curl -sSL https://install.epack.dev | bash
- name: Collect AWS posture
run: |
epack collect
# epack.yaml should have:
# collectors:
# aws:
# source: "locktivity/epack-collector-aws@^0.1.0"
# config:
# auth_mode: "oidc"
# role_arn: "arn:aws:iam::123456789012:role/EpackCollectorRole"
# secrets:
# - ACTIONS_ID_TOKEN_REQUEST_URL
# - ACTIONS_ID_TOKEN_REQUEST_TOKEN
The secrets field tells epack to pass through the ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN environment variables (provided by GitHub when id-token: write permission is set). The collector uses these to obtain an OIDC token.
If OIDC isn't available, use aws-actions/configure-aws-credentials to obtain bootstrap credentials:
name: Security Posture Collection
on:
schedule:
- cron: '0 6 * * *'
workflow_dispatch:
jobs:
collect:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::BOOTSTRAP_ACCOUNT:role/BootstrapRole
aws-region: us-east-1
- name: Install epack
run: |
curl -sSL https://install.epack.dev | bash
- name: Collect AWS posture
run: |
epack collect
# epack.yaml should have:
# collectors:
# aws:
# source: "locktivity/epack-collector-aws@^0.1.0"
# config:
# auth_mode: "assume_role"
# role_arn: "arn:aws:iam::TARGET_ACCOUNT:role/EpackCollectorRole"
# external_id: "your-external-id"
# First, create the GitHub OIDC provider (once per account)
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = ["ffffffffffffffffffffffffffffffffffffffff"]
}
resource "aws_iam_role" "epack_collector" {
name = "EpackCollectorRole"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Federated = aws_iam_openid_connect_provider.github.arn
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
}
StringLike = {
"token.actions.githubusercontent.com:sub" = "repo:${var.github_org}/${var.github_repo}:*"
}
}
}
]
})
}
resource "aws_iam_role_policy_attachment" "epack_collector" {
role = aws_iam_role.epack_collector.name
policy_arn = aws_iam_policy.epack_collector.arn
}
variable "github_org" {
description = "GitHub organization name"
type = string
}
variable "github_repo" {
description = "GitHub repository name"
type = string
}
resource "aws_iam_role" "epack_collector" {
name = "EpackCollectorRole"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${var.collector_account_id}:root"
}
Action = "sts:AssumeRole"
Condition = {
StringEquals = {
"sts:ExternalId" = var.external_id
}
}
}
]
})
}
resource "aws_iam_role_policy_attachment" "epack_collector" {
role = aws_iam_role.epack_collector.name
policy_arn = aws_iam_policy.epack_collector.arn
}
variable "collector_account_id" {
description = "AWS account ID where the collector runs"
type = string
}
variable "external_id" {
description = "External ID for assume role"
type = string
default = "epack-collector"
}
The policy file is the trust-level (default) set from the configuration page; add the audit or internal actions listed there when your pipeline collects at those levels.
resource "aws_iam_policy" "epack_collector" {
name = "EpackCollectorPolicy"
description = "Read-only access for epack AWS collector"
# Save the trust-level policy from the configuration page's Required IAM
# Permissions section as epack-collector-policy.json next to this module.
policy = file("${path.module}/epack-collector-policy.json")
}
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.4.1...v0.4.2
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.4.0...v0.4.1
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.3.1...v0.4.0
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.3.0...v0.3.1
## What's Changed * Exclude S3 log sink buckets from logging_enabled denominator by @fhodnett in https://github.com/locktivity/epack-collector-aws/pull/1 ## New Contributors * @fhodnett made their first contribution in https://github.com/locktivity/epack-collector-aws/pull/1 **Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.2.3...v0.3.0
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.2.2...v0.2.3
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.2.1...v0.2.2
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.2.0...v0.2.1
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.16...v0.2.0
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.15...v0.1.16
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.14...v0.1.15
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.13...v0.1.14
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.12...v0.1.13
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.11...v0.1.12
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.10...v0.1.11
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.9...v0.1.10
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.8...v0.1.9
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.7...v0.1.8
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.6...v0.1.7
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.4...v0.1.5
**Full Changelog**: https://github.com/locktivity/epack-collector-aws/compare/v0.1.0...v0.1.1