@cryptotaxi247 / infra-1 / commits / 79e18baa

terraform-iam: configure OIDC for NixOS/nix releases

zimbatm committed Oct 29, 2025 at 10:53 UTC 79e18baaad01e59312099c9352c625282fbe43e0
3 files changed +207
terraform-iam/assume_github_actions_policy_document/main.tf new
+40
@@ -0,0 +1,40 @@
1 +terraform {
2 + required_providers {
3 + aws = {
4 + source = "hashicorp/aws"
5 + }
6 + }
7 +}
8 +
9 +variable "subject_filter" {
10 + type = list(string)
11 +}
12 +
13 +data "aws_caller_identity" "current" {}
14 +
15 +data "aws_iam_openid_connect_provider" "github_actions" {
16 + url = "https://token.actions.githubusercontent.com"
17 +}
18 +
19 +data "aws_iam_policy_document" "assume_github_actions" {
20 +
21 + statement {
22 + effect = "Allow"
23 + actions = ["sts:AssumeRoleWithWebIdentity"]
24 +
25 + principals {
26 + type = "Federated"
27 + identifiers = [data.aws_iam_openid_connect_provider.github_actions.arn]
28 + }
29 +
30 + condition {
31 + test = "StringLike"
32 + variable = "token.actions.githubusercontent.com:sub"
33 + values = var.subject_filter
34 + }
35 + }
36 +}
37 +
38 +output "json" {
39 + value = data.aws_iam_policy_document.assume_github_actions.json
40 +}
terraform-iam/assume_identity_center_permission_policy/main.tf new
+52
@@ -0,0 +1,52 @@
1 +terraform {
2 + required_providers {
3 + aws = {
4 + source = "hashicorp/aws"
5 + }
6 + }
7 +}
8 +
9 +variable "target_account_id" {
10 + description = "AWS account ID where the reserved SSO roles exist (the target account)."
11 + type = string
12 +}
13 +
14 +variable "sso_region" {
15 + description = "Region of the AWS IAM Identity Center instance."
16 + type = string
17 + default = "eu-north-1"
18 +}
19 +
20 +variable "permission_set_name" {
21 + description = "Name of the IAM Identity Center permission set (without the AWSReservedSSO_ prefix)."
22 + type = string
23 +}
24 +
25 +locals {
26 + reserved_role_pattern = format(
27 + "arn:aws:iam::%s:role/aws-reserved/sso.amazonaws.com/%s/AWSReservedSSO_%s_*",
28 + var.target_account_id,
29 + var.sso_region,
30 + var.permission_set_name,
31 + )
32 +}
33 +
34 +data "aws_iam_policy_document" "this" {
35 + statement {
36 + effect = "Allow"
37 + actions = ["sts:AssumeRole"]
38 + principals {
39 + type = "AWS"
40 + identifiers = [format("arn:aws:iam::%s:root", var.target_account_id)]
41 + }
42 + condition {
43 + test = "ArnLike"
44 + variable = "aws:PrincipalArn"
45 + values = [local.reserved_role_pattern]
46 + }
47 + }
48 +}
49 +
50 +output "json" {
51 + value = data.aws_iam_policy_document.this.json
52 +}
terraform-iam/nix_repo_oidc.tf new
+115
@@ -0,0 +1,115 @@
1 +# In this document we configure OIDC from GitHub to allow automatically
2 +# publishing NixOS/nix releases using GitHub Actions.
3 +#
4 +# This means that everyone with merge rights in the Nix repo can publish
5 +# releases (with a public trail).
6 +
7 +resource "aws_iam_openid_connect_provider" "github_actions" {
8 + url = "https://token.actions.githubusercontent.com"
9 +
10 + client_id_list = ["sts.amazonaws.com"]
11 + thumbprint_list = [
12 + # https://github.com/aws-actions/configure-aws-credentials/issues/357#issuecomment-1626357333
13 + "6938fd4d98bab03faadb97b34396831e3780aea1",
14 + ]
15 +}
16 +
17 +import {
18 + to = aws_iam_openid_connect_provider.github_actions
19 + id = format(
20 + "arn:aws:iam::%s:oidc-provider/token.actions.githubusercontent.com",
21 + data.aws_caller_identity.current.account_id,
22 + )
23 +}
24 +
25 +data "aws_iam_policy_document" "nix_release" {
26 + statement {
27 + effect = "Allow"
28 + actions = [
29 + "s3:GetObject",
30 + "s3:PutObject"
31 + ]
32 + # Only allow uploading in the /nix/ prefix in the bucket
33 + resources = ["arn:aws:s3:::nix-releases/nix/*"]
34 + }
35 +
36 + statement {
37 + effect = "Allow"
38 + actions = [
39 + "s3:ListBucket",
40 + "s3:ListBucketMultipartUploads"
41 + ]
42 + resources = ["arn:aws:s3:::nix-releases"]
43 + condition {
44 + test = "StringLike"
45 + variable = "s3:prefix"
46 + values = ["nix/*"]
47 + }
48 + }
49 +
50 + statement {
51 + effect = "Allow"
52 + actions = [
53 + "s3:PutObject"
54 + ]
55 + # The release also publishes the install script when it's the latest
56 + # release.
57 + resources = ["arn:aws:s3:::nix-channels/nix-latest/install"]
58 + }
59 +
60 + statement {
61 + effect = "Allow"
62 + actions = [
63 + "s3:ListBucket"
64 + ]
65 + resources = ["arn:aws:s3:::nix-channels"]
66 + condition {
67 + test = "StringLike"
68 + variable = "s3:prefix"
69 + values = ["nix-latest/*"]
70 + }
71 + }
72 +}
73 +
74 +resource "aws_iam_policy" "nix_release" {
75 + name = "nix-release"
76 + policy = data.aws_iam_policy_document.nix_release.json
77 +}
78 +
79 +data "aws_caller_identity" "current" {}
80 +
81 +module "assume_nix_releases_permission" {
82 + source = "./assume_identity_center_permission_policy"
83 + target_account_id = data.aws_caller_identity.current.account_id
84 + permission_set_name = "NixReleases"
85 + sso_region = "eu-north-1"
86 +}
87 +
88 +module "assume_nix_release" {
89 + source = "./assume_github_actions_policy_document"
90 +
91 + # Only allow to assume this role in the NixOS/nix repo, and while running
92 + # in the "releases" environment.
93 + subject_filter = ["repo:NixOS/nix:environment:releases"]
94 +}
95 +
96 +data "aws_iam_policy_document" "assume_nix_release" {
97 + source_policy_documents = [
98 + module.assume_nix_releases_permission.json,
99 + module.assume_nix_release.json,
100 + ]
101 +}
102 +
103 +resource "aws_iam_role" "nix_release" {
104 + name = "nix-release"
105 + assume_role_policy = data.aws_iam_policy_document.assume_nix_release.json
106 +}
107 +
108 +resource "aws_iam_role_policy_attachment" "nix_release_managed_policy" {
109 + role = aws_iam_role.nix_release.name
110 + policy_arn = aws_iam_policy.nix_release.arn
111 +}
112 +
113 +output "nix_release_role_arn" {
114 + value = aws_iam_role.nix_release.arn
115 +}