Compare commits

...

6 commits
1.0.0 ... main

Author SHA1 Message Date
09bb1b48c8
chore(infrastructure): upgrade tofu-module-aws-iam-ci-user to 1.1.0
Some checks failed
main / test (push) Failing after 35s
2025-07-09 09:27:11 +02:00
7a58f7e909
chore(infrastructure): upgrade aws provider to 6.2.0 2025-07-09 09:26:26 +02:00
c7927f49eb
test(module): really test the generated access key
All checks were successful
main / test (push) Successful in 2m26s
2025-04-26 18:14:37 +02:00
00ee290f29
chore(infrastructure): change the AWS account used for tests
All checks were successful
main / test (push) Successful in 1m51s
2025-04-17 17:02:05 +02:00
959edc9d00
chore(infrastructure): bootstrap CI
All checks were successful
main / test (push) Successful in 1m47s
2025-04-12 09:02:04 +02:00
51bdcc5fc0
feat(module): add default value [] to input variable assume_role_account_names 2025-04-12 09:02:02 +02:00
13 changed files with 225 additions and 40 deletions

View file

@ -0,0 +1,16 @@
---
name: 'main'
on:
push:
workflow_dispatch:
jobs:
test:
runs-on: 'self-hosted'
steps:
- uses: 'actions/checkout@v4'
- uses: "https://git.adyxax.org/adyxax/action-tofu-aws-test@1.0.0"
with:
aws-access-key-id: "${{ vars.AWS_ACCESS_KEY_ID }}"
aws-access-key-secret: "${{ secrets.AWS_ACCESS_KEY_SECRET }}"

View file

@ -2,8 +2,14 @@
All notable changes to this project will be documented in this file.
## 1.1.0 - 2025-04-12
### Added
- Added default value `[]` to input variable `assume_role_account_names`.
## 1.0.0 - 2025-04-11
### Added
- initial import
- Initial import.

1
infrastructure/tofu/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
!.terraform.lock.hcl

18
infrastructure/tofu/.terraform.lock.hcl generated Normal file
View file

@ -0,0 +1,18 @@
# This file is maintained automatically by "tofu init".
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/adyxax/forgejo" {
version = "1.1.0"
constraints = "1.1.0"
hashes = [
"h1:xa2K1rn2OzQofizev01UBKEgq4WHo3EM5/fiPCxFL/E=",
]
}
provider "registry.opentofu.org/hashicorp/aws" {
version = "6.2.0"
constraints = "6.2.0"
hashes = [
"h1:UcBl0SyNxOTHOa3Ske3ClmzA7V1S7e/I4+29DLGe85A=",
]
}

View file

@ -0,0 +1,34 @@
locals {
name = "tofu-module-aws-iam-user"
}
module "aws_iam_ci_user" {
providers = {
aws.core = aws.all["core"]
aws.root = aws.all["root"]
aws.tests = aws.all["tests"]
}
source = "git::ssh://git@git.adyxax.org/adyxax/tofu-module-aws-iam-ci-user?depth=1&ref=1.1.0"
forgejo_repository = {
name = local.name
owner = "adyxax"
}
name = local.name
tests_policy_statements = jsonencode([
{
Action = "iam:*"
Effect = "Allow"
Resource = [
"arn:aws:iam::*:user/tftest-user",
"arn:aws:iam::*:policy/${local.name}-tftest",
]
},
{
# Necessary for removing an IAM user
Action = "iam:ListVirtualMFADevices",
Effect = "Allow"
Resource = "*"
}
])
}

View file

@ -0,0 +1,32 @@
terraform {
backend "s3" {
bucket = "adyxax-tofu-states"
dynamodb_table = "tofu-states"
key = "repositories/${local.name}"
profile = "core"
region = "eu-west-3"
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "6.2.0"
}
forgejo = {
source = "adyxax/forgejo"
version = "1.1.0"
}
}
}
provider "aws" {
for_each = toset(["core", "root", "tests"])
alias = "all"
default_tags { tags = { "managed-by" = "tofu" } }
profile = each.key
region = "eu-west-3"
}
provider "forgejo" {
base_uri = "https://git.adyxax.org/"
}

83
main.tf
View file

@ -1,9 +1,10 @@
data "aws_organizations_organization" "main" {}
locals {
aws_account_ids = { for info in data.aws_organizations_organization.main.accounts :
aws_account_ids = length(var.assume_role_account_names) > 0 ? {
for info in data.aws_organizations_organization.main.accounts :
info.name => info.id
}
} : {}
}
resource "aws_iam_user" "main" {
@ -14,43 +15,47 @@ resource "aws_iam_user" "main" {
resource "aws_iam_user_policy" "main" {
name = var.name
policy = jsonencode({
Statement = concat([
{ # Assume roles in AWS sub-accounts
Action = "sts:AssumeRole"
Effect = "Allow"
Resource = [for name in var.assume_role_account_names :
format(
"arn:aws:iam::%s:role/%s",
local.aws_account_ids[name],
var.name,
)
]
},
{
Action = [
# Manage the user's own IAM access key
"iam:CreateAccessKey",
"iam:DeleteAccessKey",
"iam:UpdateAccessKey",
# Read only access to the user's IAM object
"iam:Get*",
"iam:List*",
]
Effect = "Allow"
Resource = aws_iam_user.main.arn
},
{
Action = [
# Necessary for removing an IAM user
"iam:ListVirtualMFADevices",
# Describe and list the organization accounts
"organizations:DescribeOrganization",
"organizations:List*",
]
Effect = "Allow"
Resource = "*"
},
])
Statement = concat(
length(var.assume_role_account_names) > 0 ? [
{ # Assume roles in AWS sub-accounts
Action = "sts:AssumeRole"
Effect = "Allow"
Resource = [for name in var.assume_role_account_names :
format(
"arn:aws:iam::%s:role/%s",
local.aws_account_ids[name],
var.name,
)
]
}
] : [],
[
{
Action = [
# Manage the user's own IAM access key
"iam:CreateAccessKey",
"iam:DeleteAccessKey",
"iam:UpdateAccessKey",
# Read only access to the user's IAM object
"iam:Get*",
"iam:List*",
]
Effect = "Allow"
Resource = aws_iam_user.main.arn
},
{
Action = [
# Necessary for removing an IAM user
"iam:ListVirtualMFADevices",
# Describe and list the organization accounts
"organizations:DescribeOrganization",
"organizations:List*",
]
Effect = "Allow"
Resource = "*"
},
]
)
Version = "2012-10-17"
})
user = aws_iam_user.main.name

14
main.tftest.hcl Normal file
View file

@ -0,0 +1,14 @@
provider "aws" {
profile = "tests"
region = "eu-west-3"
}
run "main" {
assert {
condition = data.external.main.result.Arn == local.expected_arn
error_message = "user ARN mismatch"
}
module {
source = "./test"
}
}

4
test/aws_config.tftpl Normal file
View file

@ -0,0 +1,4 @@
[default]
aws_access_key_id = ${aws_access_key_id}
aws_secret_access_key = ${aws_access_key_secret}
region = eu-west-3

31
test/main.tf Normal file
View file

@ -0,0 +1,31 @@
module "main" {
source = "../"
name = "tftest-user"
}
data "aws_caller_identity" "current" {}
# tflint-ignore: terraform_unused_declarations
data "external" "main" {
program = ["${path.module}/test.sh"]
depends_on = [local_file.aws_config]
}
locals {
# tflint-ignore: terraform_unused_declarations
expected_arn = format(
"arn:aws:iam::%s:user/tftest-user",
data.aws_caller_identity.current.account_id,
)
}
resource "local_file" "aws_config" {
filename = "${path.module}/aws_config"
file_permission = "0600"
content = templatefile("${path.module}/aws_config.tftpl", {
aws_access_key_id = module.main.access_key_id
aws_access_key_secret = module.main.access_key_secret
})
}

15
test/providers.tf Normal file
View file

@ -0,0 +1,15 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
}
external = {
source = "hashicorp/external"
version = "2.3.4"
}
local = {
source = "hashicorp/local"
version = "2.5.2"
}
}
}

8
test/test.sh Executable file
View file

@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
# Wait a bit for the ACCESS KEY to be usable on AWS
sleep 10
export AWS_CONFIG_FILE="${PWD}/test/aws_config"
aws sts get-caller-identity

View file

@ -1,4 +1,5 @@
variable "assume_role_account_names" {
default = []
description = "The names of the AWS sub-accounts this IAM user can assume roles in."
nullable = false
type = list(string)