Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cc97a9308d | |||
| c2ca0e4631 |
@@ -112,6 +112,8 @@ def adapt(stack_instance, out_dir):
|
|||||||
|
|
||||||
stack_name = stack.get("name", "spike")
|
stack_name = stack.get("name", "spike")
|
||||||
environment = stack.get("environment", "dev")
|
environment = stack.get("environment", "dev")
|
||||||
|
account_id = os.environ.get("ACDL_AWS_ACCOUNT_ID", "581513795199")
|
||||||
|
state_bucket = f"acdl-tfstate-{account_id}-us-east-1"
|
||||||
terraform_tf = (
|
terraform_tf = (
|
||||||
'terraform {\n'
|
'terraform {\n'
|
||||||
' required_version = ">= 1.9, < 1.10"\n'
|
' required_version = ">= 1.9, < 1.10"\n'
|
||||||
@@ -122,7 +124,7 @@ def adapt(stack_instance, out_dir):
|
|||||||
' }\n'
|
' }\n'
|
||||||
' }\n'
|
' }\n'
|
||||||
' backend "s3" {\n'
|
' backend "s3" {\n'
|
||||||
' bucket = "acdl-tfstate-581513795199-us-east-1"\n'
|
f' bucket = "{state_bucket}"\n'
|
||||||
f' key = "spike/{stack_name}/{environment}/terraform.tfstate"\n'
|
f' key = "spike/{stack_name}/{environment}/terraform.tfstate"\n'
|
||||||
' region = "us-east-1"\n'
|
' region = "us-east-1"\n'
|
||||||
' }\n'
|
' }\n'
|
||||||
@@ -137,7 +139,7 @@ def adapt(stack_instance, out_dir):
|
|||||||
'data "terraform_remote_state" "platform" {\n'
|
'data "terraform_remote_state" "platform" {\n'
|
||||||
' backend = "s3"\n'
|
' backend = "s3"\n'
|
||||||
' config = {\n'
|
' config = {\n'
|
||||||
' bucket = "acdl-tfstate-581513795199-us-east-1"\n'
|
f' bucket = "{state_bucket}"\n'
|
||||||
f' key = "{remote_state_key}"\n'
|
f' key = "{remote_state_key}"\n'
|
||||||
' region = "us-east-1"\n'
|
' region = "us-east-1"\n'
|
||||||
' }\n'
|
' }\n'
|
||||||
|
|||||||
@@ -421,8 +421,10 @@ def _check_s3_state_bucket() -> Tuple[Status, str]:
|
|||||||
s3 = boto3.client("s3", region_name=env.get("AWS_DEFAULT_REGION", "us-east-1"),
|
s3 = boto3.client("s3", region_name=env.get("AWS_DEFAULT_REGION", "us-east-1"),
|
||||||
aws_access_key_id=env.get("AWS_ACCESS_KEY_ID"),
|
aws_access_key_id=env.get("AWS_ACCESS_KEY_ID"),
|
||||||
aws_secret_access_key=env.get("AWS_SECRET_ACCESS_KEY"))
|
aws_secret_access_key=env.get("AWS_SECRET_ACCESS_KEY"))
|
||||||
s3.head_bucket(Bucket="acdl-tfstate-581513795199-us-east-1")
|
account_id = os.environ.get("ACDL_AWS_ACCOUNT_ID", "581513795199")
|
||||||
r = s3.list_objects_v2(Bucket="acdl-tfstate-581513795199-us-east-1", MaxKeys=5)
|
state_bucket = f"acdl-tfstate-{account_id}-us-east-1"
|
||||||
|
s3.head_bucket(Bucket=state_bucket)
|
||||||
|
r = s3.list_objects_v2(Bucket=state_bucket, MaxKeys=5)
|
||||||
keys = [o["Key"] for o in r.get("Contents", [])]
|
keys = [o["Key"] for o in r.get("Contents", [])]
|
||||||
return "Verified", f"state bucket exists, keys={keys}"
|
return "Verified", f"state bucket exists, keys={keys}"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"wires": [
|
"wires": [
|
||||||
{"from": "contract.inputs.name", "to": "alb.inputs.name", "default": "app"},
|
{"from": "contract.inputs.name", "to": "alb.inputs.name", "default": "app"},
|
||||||
{"from": "contract.inputs.name", "to": "ecr.inputs.name", "default": "app-repo"},
|
{"from": "contract.inputs.name", "to": "ecr.inputs.name", "default": "app-repo"},
|
||||||
{"from": "contract.inputs.name", "to": "roles.inputs.role_name", "default": "app-role"},
|
{"from": "contract.inputs.name", "to": "roles.inputs.role_name", "default": "acdl-app-role"},
|
||||||
{"from": "contract.inputs.region", "to": "cluster.inputs.region"},
|
{"from": "contract.inputs.region", "to": "cluster.inputs.region"},
|
||||||
{"from": "contract.inputs.region", "to": "ecr.inputs.region"},
|
{"from": "contract.inputs.region", "to": "ecr.inputs.region"},
|
||||||
{"from": "contract.inputs.region", "to": "roles.inputs.region"},
|
{"from": "contract.inputs.region", "to": "roles.inputs.region"},
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import boto3
|
|||||||
|
|
||||||
REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent
|
REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent
|
||||||
ENV_FILE = REPO_ROOT / ".env.secrets"
|
ENV_FILE = REPO_ROOT / ".env.secrets"
|
||||||
AWS_ACCOUNT_ID = "581513795199"
|
AWS_ACCOUNT_ID = os.environ.get("ACDL_AWS_ACCOUNT_ID", "581513795199")
|
||||||
AWS_REGION = "us-east-1"
|
AWS_REGION = "us-east-1"
|
||||||
ECR_REPO_NAME = "acdl-microservice"
|
ECR_REPO_NAME = "acdl-microservice"
|
||||||
IMAGE_TAG = "latest"
|
IMAGE_TAG = "latest"
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import boto3
|
|||||||
|
|
||||||
ROOT = Path(__file__).resolve().parent.parent.parent
|
ROOT = Path(__file__).resolve().parent.parent.parent
|
||||||
POLICY_PATH = ROOT / "terraform" / "bootstrap" / "spike_runner_policy.json"
|
POLICY_PATH = ROOT / "terraform" / "bootstrap" / "spike_runner_policy.json"
|
||||||
ACCOUNT = "581513795199"
|
ACCOUNT = os.environ.get("ACDL_AWS_ACCOUNT_ID", "581513795199")
|
||||||
USER = "acdl-spike-runner"
|
USER = "acdl-spike-runner"
|
||||||
POLICY_NAME = "acdl-spike-runner-policy"
|
POLICY_NAME = "acdl-spike-runner-policy"
|
||||||
POLICY_ARN = f"arn:aws:iam::{ACCOUNT}:policy/{POLICY_NAME}"
|
POLICY_ARN = f"arn:aws:iam::{ACCOUNT}:policy/{POLICY_NAME}"
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ import boto3
|
|||||||
|
|
||||||
|
|
||||||
REGION = os.environ.get("AWS_DEFAULT_REGION", "us-east-1")
|
REGION = os.environ.get("AWS_DEFAULT_REGION", "us-east-1")
|
||||||
STATE_BUCKET = "acdl-tfstate-581513795199-us-east-1"
|
ACCOUNT_ID = os.environ.get("ACDL_AWS_ACCOUNT_ID", "581513795199")
|
||||||
|
STATE_BUCKET = f"acdl-tfstate-{ACCOUNT_ID}-us-east-1"
|
||||||
OUTBOX_TABLE = "acdl-outbox"
|
OUTBOX_TABLE = "acdl-outbox"
|
||||||
ACCOUNT_ID = "581513795199"
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@@ -215,7 +215,10 @@
|
|||||||
"kms:TagResource",
|
"kms:TagResource",
|
||||||
"kms:UntagResource"
|
"kms:UntagResource"
|
||||||
],
|
],
|
||||||
"Resource": "*"
|
"Resource": [
|
||||||
|
"arn:aws:kms:*:*:key/*",
|
||||||
|
"arn:aws:kms:*:*:alias/acdl-*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Effect": "Allow",
|
"Effect": "Allow",
|
||||||
@@ -233,7 +236,7 @@
|
|||||||
"iam:TagRole",
|
"iam:TagRole",
|
||||||
"iam:UntagRole"
|
"iam:UntagRole"
|
||||||
],
|
],
|
||||||
"Resource": "*"
|
"Resource": "arn:aws:iam::*:role/acdl-*"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,4 +176,43 @@ class TestIAMPolicyBaseline:
|
|||||||
res = s.get("Resource", "")
|
res = s.get("Resource", "")
|
||||||
if isinstance(res, list):
|
if isinstance(res, list):
|
||||||
res = " ".join(res)
|
res = " ".join(res)
|
||||||
assert res != "*", "iam:PassRole must not be granted to Resource: *"
|
assert res != "*", "iam:PassRole must not be granted to Resource: *"
|
||||||
|
|
||||||
|
def test_iam_role_creation_scoped_to_acdl_prefix(self, policy):
|
||||||
|
"""G-104: iam:CreateRole must be scoped to role/acdl-* (not Resource: *)."""
|
||||||
|
for s in policy["Statement"]:
|
||||||
|
acts = s.get("Action", [])
|
||||||
|
if isinstance(acts, str):
|
||||||
|
acts = [acts]
|
||||||
|
if "iam:CreateRole" in acts:
|
||||||
|
res = s.get("Resource", "")
|
||||||
|
if isinstance(res, list):
|
||||||
|
res = " ".join(res)
|
||||||
|
assert "acdl-*" in res, f"iam:CreateRole must be scoped to acdl-* (got: {res})"
|
||||||
|
|
||||||
|
def test_kms_scoped_to_acdl_alias(self, policy):
|
||||||
|
"""G-104: kms:CreateKey etc. must be scoped to alias/acdl-* (not Resource: *)."""
|
||||||
|
for s in policy["Statement"]:
|
||||||
|
acts = s.get("Action", [])
|
||||||
|
if isinstance(acts, str):
|
||||||
|
acts = [acts]
|
||||||
|
if any(a.startswith("kms:") for a in acts):
|
||||||
|
res = s.get("Resource", "")
|
||||||
|
if isinstance(res, list):
|
||||||
|
res = " ".join(res)
|
||||||
|
assert "acdl-*" in res, f"kms actions must be scoped to acdl-* (got: {res})"
|
||||||
|
|
||||||
|
def test_cloudfront_waf_remain_global(self, policy):
|
||||||
|
"""G-104: CloudFront + WAFv2 (CloudFront scope) ARNs are global;
|
||||||
|
Resource: * is acceptable here (documented constraint, not a defect)."""
|
||||||
|
global_actions = {"cloudfront:", "wafv2:"}
|
||||||
|
for s in policy["Statement"]:
|
||||||
|
acts = s.get("Action", [])
|
||||||
|
if isinstance(acts, str):
|
||||||
|
acts = [acts]
|
||||||
|
if any(any(a.startswith(g) for g in global_actions) for a in acts):
|
||||||
|
res = s.get("Resource", "")
|
||||||
|
if isinstance(res, list):
|
||||||
|
res = res[0] if res else ""
|
||||||
|
# CloudFront/WAFv2 are allowed to be * (global ARNs)
|
||||||
|
assert res == "*" or "acdl" in res
|
||||||
Reference in New Issue
Block a user