feat(landingzone): add minimal AWS Landing Zone baseline module
- Introduce minimal landingzone module with account-level IAM baseline: - deny-root.json - deny-no-mfa.json (MFA enforced) - deny-console-write.json (Console readonly mode) - deny-ri-sp.json (deny Reserved Instances / Savings Plans purchases)
This commit is contained in:
parent
f2c9b114cf
commit
f2996804ac
@ -0,0 +1,9 @@
|
||||
region: "ap-northeast-1"
|
||||
account_id: "730335654753"
|
||||
|
||||
landingzone:
|
||||
console_mode: "readonly" # 可选:deny / readonly
|
||||
enable_risp_controls: true # 限制 RI/SP 购买
|
||||
enable_root_limited: true # 限制 root API
|
||||
enable_mfa_enforce: true # 强制 MFA
|
||||
|
||||
25
iac-template/terraform-standard/envs/dev-landingzone/.gitignore
vendored
Normal file
25
iac-template/terraform-standard/envs/dev-landingzone/.gitignore
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
# Local terraform files
|
||||
.terraform/
|
||||
.terraform.lock.hcl
|
||||
terraform.tfstate
|
||||
terraform.tfstate.backup
|
||||
|
||||
# Auto tfvars generated by CI/CD or sensitive data
|
||||
*.tfvars
|
||||
*.auto.tfvars
|
||||
*.tfvars.json
|
||||
|
||||
# IDE / editor files
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
|
||||
# AWS credentials — never commit
|
||||
.aws/
|
||||
credentials
|
||||
config
|
||||
|
||||
# OS-specific
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
init:
|
||||
terraform init --upgrade
|
||||
plan:
|
||||
terraform plan
|
||||
apply:
|
||||
terraform apply -auto-approve
|
||||
destroy:
|
||||
terraform destroy -auto-approve
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
terraform {
|
||||
backend "s3" {
|
||||
bucket = "svc-plus-iac-state"
|
||||
key = "bootstrap/dev-landingzone/terraform.tfstate"
|
||||
region = "ap-northeast-1"
|
||||
dynamodb_table = "svc-plus-iac-state-dynamodb-lock"
|
||||
}
|
||||
}
|
||||
16
iac-template/terraform-standard/envs/dev-landingzone/main.tf
Normal file
16
iac-template/terraform-standard/envs/dev-landingzone/main.tf
Normal file
@ -0,0 +1,16 @@
|
||||
locals {
|
||||
account = yamldecode(
|
||||
file("${path.root}/../../config/accounts/dev-landingzone.yaml")
|
||||
)
|
||||
}
|
||||
|
||||
module "landingzone" {
|
||||
source = "../../modules/landingzone"
|
||||
|
||||
region = local.account.region
|
||||
account_id = local.account.account_id
|
||||
console_mode = local.account.landingzone.console_mode
|
||||
enable_risp_controls = local.account.landingzone.enable_risp_controls
|
||||
enable_root_limited = local.account.landingzone.enable_root_limited
|
||||
enable_mfa_enforce = local.account.landingzone.enable_mfa_enforce
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
terraform {
|
||||
required_version = ">= 1.2"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.92.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = local.account.region
|
||||
|
||||
assume_role {
|
||||
role_arn = "arn:aws:iam::730335654753:role/TerraformDeployRole-Dev"
|
||||
session_name = "TerraformDevSession"
|
||||
}
|
||||
}
|
||||
|
||||
25
iac-template/terraform-standard/envs/dev-rds/.terraform.lock.hcl
generated
Normal file
25
iac-template/terraform-standard/envs/dev-rds/.terraform.lock.hcl
generated
Normal file
@ -0,0 +1,25 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/aws" {
|
||||
version = "5.92.0"
|
||||
constraints = "~> 5.92.0"
|
||||
hashes = [
|
||||
"h1:KS0bRFXK4N1Do9Y6olKtu4cMhcHvgGYYRHpN+VNfsnM=",
|
||||
"zh:1d3a0b40831360e8e988aee74a9ff3d69d95cb541c2eae5cb843c64303a091ba",
|
||||
"zh:3d29cbced6c708be2041a708d25c7c0fc22d09e4d0b174360ed113bfae786137",
|
||||
"zh:4341a203cf5820a0ca18bb514ae10a6c113bc6a728fb432acbf817d232e8eff4",
|
||||
"zh:4a49e2d91e4d92b6b93ccbcbdcfa2d67935ce62e33b939656766bb81b3fd9a2c",
|
||||
"zh:54c7189358b37fd895dedbabf84e509c1980a8c404a1ee5b29b06e40497b8655",
|
||||
"zh:5d8bb1ff089c37cb65c83b4647f1981fded993e87d8132915d92d79f29e2fcd8",
|
||||
"zh:618f2eb87cd65b245aefba03991ad714a51ff3b841016ef68e2da2b85d0b2325",
|
||||
"zh:7bce07bc542d0588ca42bac5098dd4f8af715417cd30166b4fb97cedd44ab109",
|
||||
"zh:81419eab2d8810beb114b1ff5cbb592d21edc21b809dc12bb066e4b88fdd184a",
|
||||
"zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
|
||||
"zh:9dea39d4748eeeebe2e76ca59bca4ccd161c2687050878c47289a98407a23372",
|
||||
"zh:d692fc33b67ac89e916c8f9233d39eacab8c438fe10172990ee9d94fba5ca372",
|
||||
"zh:d9075c7da48947c029ba47d5985e1e8e3bf92367bfee8ca1ff0e747765e779a1",
|
||||
"zh:e81c62db317f3b640b2e04eba0ada8aa606bcbae0152c09f6242e86b86ef5889",
|
||||
"zh:f68562e073722c378d2f3529eb80ad463f12c44aa5523d558ae3b69f4de5ca1f",
|
||||
]
|
||||
}
|
||||
20
iac-template/terraform-standard/envs/dev-rds/provider.tf
Normal file
20
iac-template/terraform-standard/envs/dev-rds/provider.tf
Normal file
@ -0,0 +1,20 @@
|
||||
terraform {
|
||||
required_version = ">= 1.2"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.92.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = local.account.region
|
||||
|
||||
assume_role {
|
||||
role_arn = "arn:aws:iam::730335654753:role/TerraformDeployRole-Dev"
|
||||
session_name = "TerraformDevSession"
|
||||
}
|
||||
}
|
||||
|
||||
40
iac-template/terraform-standard/modules/landingzone/main.tf
Normal file
40
iac-template/terraform-standard/modules/landingzone/main.tf
Normal file
@ -0,0 +1,40 @@
|
||||
locals {
|
||||
root_policy = var.enable_root_limited ? "deny-root.json" : null
|
||||
mfa_policy = var.enable_mfa_enforce ? "deny-no-mfa.json" : null
|
||||
console_policy = var.console_mode == "readonly" ? "deny-console-write.json" : null
|
||||
risp_policy = var.enable_risp_controls ? "deny-ri-sp.json" : null
|
||||
|
||||
policies = compact([
|
||||
local.root_policy,
|
||||
local.mfa_policy,
|
||||
local.console_policy,
|
||||
local.risp_policy
|
||||
])
|
||||
}
|
||||
|
||||
#
|
||||
# Baseline IAM group
|
||||
#
|
||||
resource "aws_iam_group" "baseline" {
|
||||
name = "LandingZoneBaseline"
|
||||
}
|
||||
|
||||
#
|
||||
# Create IAM policies
|
||||
#
|
||||
resource "aws_iam_policy" "baseline" {
|
||||
for_each = toset(local.policies)
|
||||
|
||||
name = "landingzone-${replace(each.value, ".json", "")}"
|
||||
policy = file("${path.module}/policies/${each.value}")
|
||||
}
|
||||
|
||||
#
|
||||
# Attach policies to baseline group
|
||||
#
|
||||
resource "aws_iam_group_policy_attachment" "attach" {
|
||||
for_each = aws_iam_policy.baseline
|
||||
|
||||
group = aws_iam_group.baseline.name
|
||||
policy_arn = each.value.arn
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
output "policy_arns" {
|
||||
value = { for k, v in aws_iam_policy.baseline : k => v.arn }
|
||||
}
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "DenyWriteActionsForIAMUsers",
|
||||
"Effect": "Deny",
|
||||
"NotAction": [
|
||||
"iam:Get*",
|
||||
"iam:List*",
|
||||
"sts:GetCallerIdentity",
|
||||
"ec2:Describe*",
|
||||
"s3:Get*",
|
||||
"s3:List*",
|
||||
"eks:Describe*",
|
||||
"eks:List*",
|
||||
"cloudwatch:Get*",
|
||||
"cloudwatch:List*"
|
||||
],
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"StringLike": {
|
||||
"aws:username": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "DenyUnlessMFA",
|
||||
"Effect": "Deny",
|
||||
"NotAction": [
|
||||
"iam:CreateVirtualMFADevice",
|
||||
"iam:EnableMFADevice",
|
||||
"iam:ListMFADevices",
|
||||
"iam:ResyncMFADevice",
|
||||
"sts:GetSessionToken",
|
||||
"sts:GetCallerIdentity"
|
||||
],
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"BoolIfExists": {
|
||||
"aws:MultiFactorAuthPresent": "false"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "DenyReservedInstancesPurchaseForNonFinOps",
|
||||
"Effect": "Deny",
|
||||
"Action": [
|
||||
"ec2:PurchaseReservedInstancesOffering",
|
||||
"ec2:ModifyReservedInstances"
|
||||
],
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"StringNotEquals": {
|
||||
"aws:PrincipalArn": "arn:aws:iam::<ACCOUNT_ID>:role/FinOpsRole"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Sid": "DenySavingsPlansPurchaseForNonFinOps",
|
||||
"Effect": "Deny",
|
||||
"Action": [
|
||||
"savingsplans:CreateSavingsPlan",
|
||||
"savingsplans:DeleteQueuedSavingsPlan"
|
||||
],
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"StringNotEquals": {
|
||||
"aws:PrincipalArn": "arn:aws:iam::<ACCOUNT_ID>:role/FinOpsRole"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "RootLimitedActions",
|
||||
"Effect": "Deny",
|
||||
"NotAction": [
|
||||
"aws-portal:*",
|
||||
"iam:CreateVirtualMFADevice",
|
||||
"iam:EnableMFADevice",
|
||||
"iam:ListMFADevices",
|
||||
"iam:ResyncMFADevice",
|
||||
"iam:Get*",
|
||||
"iam:List*",
|
||||
"sts:GetCallerIdentity"
|
||||
],
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"aws:username": "root"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
variable "region" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "account_id" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "console_mode" {
|
||||
type = string
|
||||
default = "readonly"
|
||||
}
|
||||
|
||||
variable "enable_risp_controls" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "enable_root_limited" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "enable_mfa_enforce" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user