From 9dc99f758e4be4b40f2faba04812691f8547c124 Mon Sep 17 00:00:00 2001 From: sohan yadav Date: Tue, 16 Sep 2025 11:53:48 +0530 Subject: [PATCH] fix tags --- .gitignore | 212 ++++++++++++++++++++++++++- bitbucket.tf | 2 +- github.tf | 2 +- gitlab.tf | 3 +- groups.tf | 3 +- iam-group-with-policies/main.tf | 64 ++++++++ iam-group-with-policies/outputs.tf | 19 +++ iam-group-with-policies/policies.tf | 182 +++++++++++++++++++++++ iam-group-with-policies/variables.tf | 65 ++++++++ 9 files changed, 545 insertions(+), 7 deletions(-) create mode 100644 iam-group-with-policies/main.tf create mode 100644 iam-group-with-policies/outputs.tf create mode 100644 iam-group-with-policies/policies.tf create mode 100644 iam-group-with-policies/variables.tf diff --git a/.gitignore b/.gitignore index 600d2d3..13e2c5a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,211 @@ -.vscode \ No newline at end of file +.vscode +# ignored files +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Eclipse template + +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk +### Ansible template +*.retry +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Archives template +# It's better to unpack these files and commit the raw source because +# git has its own built in compression methods. +*.7z +*.jar +*.rar +*.zip +*.gz +*.tgz +*.bzip +*.bz2 +*.xz +*.lzma +*.cab + +# Packing-only formats +*.iso +*.tar + +# Package management formats +*.dmg +*.xpi +*.gem +*.egg +*.deb +*.rpm +*.msi +*.msm +*.msp +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +/.idea/ +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +# CMake +cmake-build-debug/ + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ +# User-specific stuff: +.idea/* +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# TFstste +*.tfstate* + +deployment/_logs/ansible-log.json +deployment/_logs/ansible-log.log +deployment/_logs/facts/* +deployment/_logs/retry/* +_app/* +ansible-log.json +.terraform +terraform.tfstate + +*.tfstate +*.tfstate.backup +*.iml +*.terraform.lock.hcl +*.lock.hcl \ No newline at end of file diff --git a/bitbucket.tf b/bitbucket.tf index df88aaf..80edb96 100644 --- a/bitbucket.tf +++ b/bitbucket.tf @@ -1,7 +1,7 @@ module "bitbucket" { for_each = var.bitbucket - source = "github.com/opszero/terraform-aws-bitbucket-oidc" + source = "github.com/opszero/terraform-aws-bitbucket-oidc?ref=v1.0.0" workspace_name = each.value.workspace_name workspace_uuid = each.value.workspace_uuid diff --git a/github.tf b/github.tf index 43d036b..15cfeac 100644 --- a/github.tf +++ b/github.tf @@ -1,7 +1,7 @@ module "oidc-github" { for_each = var.github - source = "github.com/opszero/terraform-aws-oidc-github" + source = "github.com/opszero/terraform-aws-oidc-github?ref=v1.0.0" github_repositories = each.value.repos diff --git a/gitlab.tf b/gitlab.tf index 8273add..3a2c83d 100644 --- a/gitlab.tf +++ b/gitlab.tf @@ -1,8 +1,7 @@ module "aws_oidc_gitlab" { for_each = var.gitlab - source = "github.com/abhiyerra/terraform-aws-oidc-gitlab" - + source = "github.com/opszero/terraform-aws-oidc-gitlab?ref=v1.0.0" attach_admin_policy = false create_oidc_provider = true diff --git a/groups.tf b/groups.tf index 876db12..888d8c2 100644 --- a/groups.tf +++ b/groups.tf @@ -1,8 +1,7 @@ module "iam_group_with_policies" { for_each = var.groups - source = "terraform-aws-modules/iam/aws//modules/iam-group-with-policies" - version = "~> 6" + source = "./iam-group-with-policies" name = each.key diff --git a/iam-group-with-policies/main.tf b/iam-group-with-policies/main.tf new file mode 100644 index 0000000..53f6361 --- /dev/null +++ b/iam-group-with-policies/main.tf @@ -0,0 +1,64 @@ +locals { + group_name = var.create_group ? aws_iam_group.this[0].id : var.name +} + +resource "aws_iam_group" "this" { + count = var.create_group ? 1 : 0 + + name = var.name + path = var.path +} + +resource "aws_iam_group_membership" "this" { + count = length(var.group_users) > 0 ? 1 : 0 + + group = local.group_name + name = var.name + users = var.group_users +} + +################################ +# IAM group policy attachements +################################ +resource "aws_iam_group_policy_attachment" "iam_self_management" { + count = var.attach_iam_self_management_policy ? 1 : 0 + + group = local.group_name + policy_arn = aws_iam_policy.iam_self_management[0].arn +} + +resource "aws_iam_group_policy_attachment" "custom_arns" { + count = length(var.custom_group_policy_arns) + + group = local.group_name + policy_arn = element(var.custom_group_policy_arns, count.index) +} + +resource "aws_iam_group_policy_attachment" "custom" { + count = length(var.custom_group_policies) + + group = local.group_name + policy_arn = element(aws_iam_policy.custom[*].arn, count.index) +} + +############### +# IAM policies +############### +resource "aws_iam_policy" "iam_self_management" { + count = var.attach_iam_self_management_policy ? 1 : 0 + + name_prefix = var.iam_self_management_policy_name_prefix + policy = data.aws_iam_policy_document.iam_self_management.json + + tags = var.tags +} + +resource "aws_iam_policy" "custom" { + count = length(var.custom_group_policies) + + name = var.custom_group_policies[count.index]["name"] + policy = var.custom_group_policies[count.index]["policy"] + description = lookup(var.custom_group_policies[count.index], "description", null) + + tags = var.tags +} diff --git a/iam-group-with-policies/outputs.tf b/iam-group-with-policies/outputs.tf new file mode 100644 index 0000000..ee0835c --- /dev/null +++ b/iam-group-with-policies/outputs.tf @@ -0,0 +1,19 @@ +output "aws_account_id" { + description = "IAM AWS account id" + value = local.aws_account_id +} + +output "group_arn" { + description = "IAM group arn" + value = try(aws_iam_group.this[0].arn, "") +} + +output "group_users" { + description = "List of IAM users in IAM group" + value = flatten(aws_iam_group_membership.this[*].users) +} + +output "group_name" { + description = "IAM group name" + value = try(aws_iam_group.this[0].name, var.name) +} diff --git a/iam-group-with-policies/policies.tf b/iam-group-with-policies/policies.tf new file mode 100644 index 0000000..ca071f8 --- /dev/null +++ b/iam-group-with-policies/policies.tf @@ -0,0 +1,182 @@ +data "aws_caller_identity" "current" { + count = var.aws_account_id == "" ? 1 : 0 +} + +data "aws_partition" "current" {} + +locals { + aws_account_id = try(data.aws_caller_identity.current[0].account_id, var.aws_account_id) + partition = data.aws_partition.current.partition +} + +# Allows MFA-authenticated IAM users to manage their own credentials on the My security credentials page +# https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_aws_my-sec-creds-self-manage.html +data "aws_iam_policy_document" "iam_self_management" { + statement { + sid = "AllowViewAccountInfo" + + effect = "Allow" + + actions = [ + "iam:GetAccountSummary", + "iam:GetAccountPasswordPolicy", + "iam:ListAccountAliases", + "iam:ListVirtualMFADevices" + ] + + resources = ["*"] + } + + statement { + sid = "AllowManageOwnPasswords" + + effect = "Allow" + + actions = [ + "iam:ChangePassword", + "iam:GetLoginProfile", + "iam:GetUser", + "iam:UpdateLoginProfile" + ] + + resources = [ + "arn:${local.partition}:iam::${local.aws_account_id}:user/$${aws:username}", + "arn:${local.partition}:iam::${local.aws_account_id}:user/*/$${aws:username}" + ] + } + + statement { + sid = "AllowManageOwnAccessKeys" + + effect = "Allow" + + actions = [ + "iam:CreateAccessKey", + "iam:DeleteAccessKey", + "iam:ListAccessKeys", + "iam:UpdateAccessKey", + "iam:GetAccessKeyLastUsed", + "iam:TagUser", + "iam:ListUserTags", + "iam:UntagUser", + ] + + resources = [ + "arn:${local.partition}:iam::${local.aws_account_id}:user/$${aws:username}", + "arn:${local.partition}:iam::${local.aws_account_id}:user/*/$${aws:username}" + ] + } + + statement { + sid = "AllowManageOwnSigningCertificates" + + effect = "Allow" + + actions = [ + "iam:DeleteSigningCertificate", + "iam:ListSigningCertificates", + "iam:UpdateSigningCertificate", + "iam:UploadSigningCertificate" + ] + + resources = [ + "arn:${local.partition}:iam::${local.aws_account_id}:user/$${aws:username}", + "arn:${local.partition}:iam::${local.aws_account_id}:user/*/$${aws:username}" + ] + } + + statement { + sid = "AllowManageOwnSSHPublicKeys" + + effect = "Allow" + + actions = [ + "iam:DeleteSSHPublicKey", + "iam:GetSSHPublicKey", + "iam:ListSSHPublicKeys", + "iam:UpdateSSHPublicKey", + "iam:UploadSSHPublicKey" + ] + + resources = [ + "arn:${local.partition}:iam::${local.aws_account_id}:user/$${aws:username}", + "arn:${local.partition}:iam::${local.aws_account_id}:user/*/$${aws:username}" + ] + } + + statement { + sid = "AllowManageOwnGitCredentials" + + effect = "Allow" + + actions = [ + "iam:CreateServiceSpecificCredential", + "iam:DeleteServiceSpecificCredential", + "iam:ListServiceSpecificCredentials", + "iam:ResetServiceSpecificCredential", + "iam:UpdateServiceSpecificCredential" + ] + + resources = [ + "arn:${local.partition}:iam::${local.aws_account_id}:user/$${aws:username}", + "arn:${local.partition}:iam::${local.aws_account_id}:user/*/$${aws:username}" + ] + } + + statement { + sid = "AllowManageOwnVirtualMFADevice" + + effect = "Allow" + + actions = [ + "iam:CreateVirtualMFADevice" + ] + + resources = ["arn:${local.partition}:iam::${local.aws_account_id}:mfa/*"] + } + + statement { + sid = "AllowManageOwnUserMFA" + + effect = "Allow" + + actions = [ + "iam:DeactivateMFADevice", + "iam:EnableMFADevice", + "iam:ListMFADevices", + "iam:ResyncMFADevice" + ] + + resources = [ + "arn:${local.partition}:iam::${local.aws_account_id}:user/$${aws:username}", + "arn:${local.partition}:iam::${local.aws_account_id}:user/*/$${aws:username}" + ] + } + + dynamic "statement" { + for_each = var.enable_mfa_enforcement ? [1] : [] + + content { + sid = "DenyAllExceptListedIfNoMFA" + effect = "Deny" + not_actions = [ + "iam:CreateVirtualMFADevice", + "iam:EnableMFADevice", + "iam:GetUser", + "iam:GetMFADevice", + "iam:ListMFADevices", + "iam:ListVirtualMFADevices", + "iam:ResyncMFADevice", + "sts:GetSessionToken", + "iam:ChangePassword" + ] + resources = ["*"] + + condition { + test = "BoolIfExists" + variable = "aws:MultiFactorAuthPresent" + values = ["false"] + } + } + } +} diff --git a/iam-group-with-policies/variables.tf b/iam-group-with-policies/variables.tf new file mode 100644 index 0000000..59bf729 --- /dev/null +++ b/iam-group-with-policies/variables.tf @@ -0,0 +1,65 @@ +variable "create_group" { + description = "Whether to create IAM group" + type = bool + default = true +} + +variable "name" { + description = "Name of IAM group" + type = string + default = "" +} + +variable "path" { + description = "Desired path for the IAM group" + type = string + default = "/" +} + +variable "group_users" { + description = "List of IAM users to have in an IAM group which can assume the role" + type = list(string) + default = [] +} + +variable "custom_group_policy_arns" { + description = "List of IAM policies ARNs to attach to IAM group" + type = list(string) + default = [] +} + +variable "custom_group_policies" { + description = "List of maps of inline IAM policies to attach to IAM group. Should have `name` and `policy` keys in each element." + type = list(map(string)) + default = [] +} + +variable "enable_mfa_enforcement" { + description = "Determines whether permissions are added to the policy which requires the groups IAM users to use MFA" + type = bool + default = true +} + +variable "attach_iam_self_management_policy" { + description = "Whether to attach IAM policy which allows IAM users to manage their credentials and MFA" + type = bool + default = true +} + +variable "iam_self_management_policy_name_prefix" { + description = "Name prefix for IAM policy to create with IAM self-management permissions" + type = string + default = "IAMSelfManagement-" +} + +variable "aws_account_id" { + description = "AWS account id to use inside IAM policies. If empty, current AWS account ID will be used." + type = string + default = "" +} + +variable "tags" { + description = "A map of tags to add to all resources." + type = map(string) + default = {} +}