Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions src/tf/federated-identity.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
resource "aws_iam_openid_connect_provider" "sgfdevs_k3s" {
url = "https://k8s-oidc.sgf.dev"

client_id_list = [
"sts.amazonaws.com"
]

tags = {
Environment = "global"
ManagedBy = "OpenTofu"
Name = "sgfdevs-k3s-oidc"
Repository = "sgfdevs/infra-vm-workloads"
}
}

resource "aws_iam_policy" "sgfdevs_k3s_kubernetes_workload_boundary" {
name = "SGFDevsK3sKubernetesWorkloadBoundary"
path = "/sgfdevs-k3s/"
description = "Require SGF Devs K3s workload roles to be used only by Kubernetes service accounts"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "AllowWorkloadPermissions"
Effect = "Allow"
Action = "*"
Resource = "*"
},
{
Sid = "DenyOtherFederatedProviders"
Effect = "Deny"
Action = "*"
Resource = "*"
Condition = {
ArnNotEquals = {
"aws:FederatedProvider" = aws_iam_openid_connect_provider.sgfdevs_k3s.arn
}
}
},
{
Sid = "DenyNonServiceAccountSubjects"
Effect = "Deny"
Action = "*"
Resource = "*"
Condition = {
StringNotLike = {
"k8s-oidc.sgf.dev:sub" = "system:serviceaccount:*:*"
}
}
},
{
Sid = "DenyUnexpectedAudience"
Effect = "Deny"
Action = "*"
Resource = "*"
Condition = {
StringNotEquals = {
"k8s-oidc.sgf.dev:aud" = "sts.amazonaws.com"
}
}
},
{
Sid = "DenyPrivilegeEscalation"
Effect = "Deny"
Action = [
"account:*",
"iam:*",
"identitystore:*",
"organizations:*",
"sso:*",
"sso-directory:*",
"sts:AssumeRole",
"sts:AssumeRoleWithSAML",
"sts:AssumeRoleWithWebIdentity",
"sts:GetFederationToken",
"sts:GetSessionToken",
]
Resource = "*"
},
]
})

tags = {
Environment = "global"
ManagedBy = "OpenTofu"
Name = "sgfdevs-k3s-kubernetes-workload-boundary"
}
}
18 changes: 10 additions & 8 deletions src/tf/github-actions.tf
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
module "github_actions" {
source = "./modules/github-actions"

application_ses_policy_arns = local.application_ses_policy_arns
application_ses_senders = local.application_ses_senders
aws_account_id = data.aws_caller_identity.current.account_id
oidc_provider_arn = aws_iam_openid_connect_provider.github_actions.arn
ses_identity_arns = [for identity in aws_sesv2_email_identity.domain : identity.arn]
state_bucket_arn = aws_s3_bucket.tfstate_state.arn
state_bucket_name = aws_s3_bucket.tfstate_state.bucket
state_lock_table_arn = aws_dynamodb_table.tflock_state.arn
application_ses_policy_arns = local.application_ses_policy_arns
application_ses_senders = local.application_ses_senders
aws_account_id = data.aws_caller_identity.current.account_id
oidc_provider_arn = aws_iam_openid_connect_provider.github_actions.arn
ses_identity_arns = [for identity in aws_sesv2_email_identity.domain : identity.arn]
sgfdevs_k3s_oidc_provider_arn = aws_iam_openid_connect_provider.sgfdevs_k3s.arn
sgfdevs_k3s_workload_boundary_arn = aws_iam_policy.sgfdevs_k3s_kubernetes_workload_boundary.arn
state_bucket_arn = aws_s3_bucket.tfstate_state.arn
state_bucket_name = aws_s3_bucket.tfstate_state.bucket
state_lock_table_arn = aws_dynamodb_table.tflock_state.arn
vm_workloads_bootstrap_parameter_arns = [
"arn:aws:ssm:${var.aws_region}:${data.aws_caller_identity.current.account_id}:parameter${local.sgfdevs_vms_eso_access_key_id_path}",
"arn:aws:ssm:${var.aws_region}:${data.aws_caller_identity.current.account_id}:parameter${local.sgfdevs_vms_eso_secret_access_key_path}",
Expand Down
83 changes: 83 additions & 0 deletions src/tf/modules/github-actions/infra-vm-workloads.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
locals {
vm_workloads_workload_role_arn_pattern = "arn:aws:iam::${var.aws_account_id}:role/sgfdevs-k3s/*"
}

resource "aws_iam_role_policy" "github_actions_vm_workloads" {
name = "InfraVMWorkloadsRepositoryAccess"
role = aws_iam_role.github_actions["vm_workloads"].id
Expand Down Expand Up @@ -35,6 +39,28 @@ resource "aws_iam_role_policy" "github_actions_vm_workloads" {
Action = "ssm:DescribeParameters"
Resource = "*"
},
{
Sid = "ReadSGFDevsK3sOIDCProvider"
Effect = "Allow"
Action = [
"iam:GetOpenIDConnectProvider",
"iam:ListOpenIDConnectProviderTags",
]
Resource = var.sgfdevs_k3s_oidc_provider_arn
},
{
Sid = "ReadSGFDevsK3sWorkloadRole"
Effect = "Allow"
Action = [
"iam:GetRole",
"iam:GetRolePolicy",
"iam:ListAttachedRolePolicies",
"iam:ListInstanceProfilesForRole",
"iam:ListRolePolicies",
"iam:ListRoleTags",
]
Resource = local.vm_workloads_workload_role_arn_pattern
},
{
Sid = "ManageWorkloadParametersFromMain"
Effect = "Allow"
Expand All @@ -49,6 +75,63 @@ resource "aws_iam_role_policy" "github_actions_vm_workloads" {
}
}
},
{
Sid = "CreateSGFDevsK3sWorkloadRoleFromMain"
Effect = "Allow"
Action = "iam:CreateRole"
Resource = local.vm_workloads_workload_role_arn_pattern
Condition = {
StringEquals = {
"iam:PermissionsBoundary" = var.sgfdevs_k3s_workload_boundary_arn
"token.actions.githubusercontent.com:sub" = "$${aws:PrincipalTag/GitHubMainSubject}"
}
}
},
{
Sid = "ManageSGFDevsK3sWorkloadRoleTagsFromMain"
Effect = "Allow"
Action = [
"iam:TagRole",
"iam:UntagRole",
]
Resource = local.vm_workloads_workload_role_arn_pattern
Condition = {
"ForAllValues:StringEquals" = {
"aws:TagKeys" = [
"KubernetesNamespace",
"KubernetesServiceAccount",
"ManagedBy",
"Repository",
]
}
StringEquals = {
"token.actions.githubusercontent.com:sub" = "$${aws:PrincipalTag/GitHubMainSubject}"
}
StringEqualsIfExists = {
"aws:RequestTag/ManagedBy" = "OpenTofu"
"aws:RequestTag/Repository" = "sgfdevs/infra-vm-workloads"
}
}
},
{
Sid = "ManageBoundedSGFDevsK3sWorkloadRoleFromMain"
Effect = "Allow"
Action = [
"iam:DeleteRole",
"iam:DeleteRolePolicy",
"iam:PutRolePermissionsBoundary",
"iam:PutRolePolicy",
"iam:UpdateAssumeRolePolicy",
"iam:UpdateRole",
]
Resource = local.vm_workloads_workload_role_arn_pattern
Condition = {
StringEquals = {
"iam:PermissionsBoundary" = var.sgfdevs_k3s_workload_boundary_arn
"token.actions.githubusercontent.com:sub" = "$${aws:PrincipalTag/GitHubMainSubject}"
}
}
},
]
})
}
10 changes: 10 additions & 0 deletions src/tf/modules/github-actions/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ variable "ses_identity_arns" {
type = list(string)
}

variable "sgfdevs_k3s_oidc_provider_arn" {
description = "ARN of the Kubernetes OIDC provider for the SGF Devs K3s cluster."
type = string
}

variable "sgfdevs_k3s_workload_boundary_arn" {
description = "Permissions boundary ARN for SGF Devs K3s Kubernetes workload roles."
type = string
}

variable "state_bucket_arn" {
description = "ARN of the shared OpenTofu state bucket."
type = string
Expand Down
10 changes: 10 additions & 0 deletions src/tf/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ output "github_actions_vm_workloads_role_arn" {
sensitive = true
}

output "sgfdevs_k3s_oidc_provider_arn" {
description = "IAM OIDC provider ARN for the SGF Devs K3s cluster."
value = aws_iam_openid_connect_provider.sgfdevs_k3s.arn
}

output "sgfdevs_k3s_workload_boundary_arn" {
description = "Permissions boundary ARN for SGF Devs K3s Kubernetes workload roles."
value = aws_iam_policy.sgfdevs_k3s_kubernetes_workload_boundary.arn
}

output "ses_email_identity_arns" {
description = "ARNs of the SES identities used for outbound email."
value = { for domain, identity in aws_sesv2_email_identity.domain : domain => identity.arn }
Expand Down