From aebbd2c90fbabbb791a6acfcc0aca1e12fbb4589 Mon Sep 17 00:00:00 2001 From: Sebastian Just Date: Sun, 22 Feb 2026 11:03:03 -0500 Subject: [PATCH 1/4] Lintin --- .pre-commit-config.yaml | 34 ++++++++ Makefile | 20 +++++ README.md | 0 .../nas-backup.yml} | 80 +++++++++++++------ 4 files changed, 110 insertions(+), 24 deletions(-) create mode 100644 .pre-commit-config.yaml create mode 100644 Makefile create mode 100644 README.md rename infra/{cloudformation.yml => cfn/nas-backup.yml} (50%) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..680d4e4 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,34 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 # Get the latest from: https://github.com/pre-commit/pre-commit-hooks/releases + hooks: + - id: no-commit-to-branch + - id: check-yaml + args: [--unsafe] + - id: check-json + - id: mixed-line-ending + - id: end-of-file-fixer + - id: trailing-whitespace + - id: check-added-large-files + - id: pretty-format-json + args: ['--autofix'] + - repo: https://github.com/aws-cloudformation/cfn-lint + rev: v1.44.0 + hooks: + - id: cfn-lint + files: infra/cfn/.*\\.(json|yml|yaml)$ + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.41.0 + hooks: + - id: markdownlint + name: "Checking Markdown with markdownlint" + - repo: https://github.com/Yelp/detect-secrets + rev: v1.5.0 + hooks: + - id: detect-secrets + args: ['--baseline', '.secrets.baseline'] + exclude: package.lock.json + - repo: https://github.com/psf/black + rev: 24.4.2 + hooks: + - id: black diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..212352c --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +.PHONY: install run + + +install: + brew install tfenv + brew install pre-commit gawk coreutils cfn-lint + brew install checkov semgrep markdownlint-cli shellcheck + pre-commit install + +run: + pre-commit run -a + +update: + pre-commit autoupdate + +audit-secrets: + detect-secrets scan > .secrets.baseline + detect-secrets audit .secrets.baseline + +default: run diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/infra/cloudformation.yml b/infra/cfn/nas-backup.yml similarity index 50% rename from infra/cloudformation.yml rename to infra/cfn/nas-backup.yml index 2e32fed..a1e4867 100644 --- a/infra/cloudformation.yml +++ b/infra/cfn/nas-backup.yml @@ -1,15 +1,12 @@ AWSTemplateFormatVersion: '2010-09-09' -Description: AWS CloudFormation for nas-backup with complete Multipart and Location permissions. +Description: nas-backup stack with 3-block IAM policy for IP-restricted access. Parameters: environment: Type: String Default: prod - AllowedValues: - - dev - - stg - - prod - Description: The deployment environment (must be lowercase). + AllowedValues: [dev, stg, prod] + Description: Deployment environment (must be lowercase). Resources: # S3 Bucket @@ -40,7 +37,7 @@ Resources: - Key: 'cloudspout:repository' Value: 'cloudspout/nas-backup' - # IAM Service User + # IAM User with IP Tags NASBackupUser: Type: 'AWS::IAM::User' Properties: @@ -52,55 +49,90 @@ Resources: Value: 'nas-backup' - Key: 'cloudspout:repository' Value: 'cloudspout/nas-backup' + - Key: 'cloudspout:home-ip' + Value: '0.0.0.0/0' + - Key: 'cloudspout:fallback-ip' + Value: '0.0.0.0/0' # IAM Managed Policy NASBackupManagedPolicy: Type: 'AWS::IAM::ManagedPolicy' Properties: ManagedPolicyName: !Sub 'nas-backup-policy-${environment}' - Users: - - !Ref NASBackupUser + Users: [!Ref NASBackupUser] PolicyDocument: Version: '2012-10-17' Statement: - # 1. Account-level Global Access + # BLOCK 1: Global Account Listing (IP Restricted) - Effect: Allow - Action: - - 's3:ListAllMyBuckets' + Action: ['s3:ListAllMyBuckets'] Resource: '*' + Condition: + IpAddress: + 'aws:SourceIp': + - '${aws:PrincipalTag/cloudspout:home-ip}' + - '${aws:PrincipalTag/cloudspout:fallback-ip}' - # 2. Bucket-level Access (Listing and Configuration) + # BLOCK 2: Bucket & Object Access via Home IP - Effect: Allow Action: - 's3:ListBucket' - 's3:GetBucketLocation' - - 's3:ListBucketMultipartUploads' # Required for resuming failed large uploads + - 's3:ListBucketMultipartUploads' + - 's3:PutObject' + - 's3:GetObject' + - 's3:DeleteObject' + - 's3:AbortMultipartUpload' + - 's3:ListMultipartUploadParts' Resource: - !GetAtt NASBackupBucket.Arn + - !Sub '${NASBackupBucket.Arn}/*' + Condition: + IpAddress: + 'aws:SourceIp': '${aws:PrincipalTag/cloudspout:home-ip}' - # 3. Object-level Access (Data movement) + # BLOCK 3: Bucket & Object Access via Fallback IP - Effect: Allow Action: + - 's3:ListBucket' + - 's3:GetBucketLocation' + - 's3:ListBucketMultipartUploads' - 's3:PutObject' - 's3:GetObject' - 's3:DeleteObject' - - 's3:AbortMultipartUpload' # Required to cancel failed chunks - - 's3:ListMultipartUploadParts' # Required to verify uploaded chunks + - 's3:AbortMultipartUpload' + - 's3:ListMultipartUploadParts' Resource: + - !GetAtt NASBackupBucket.Arn - !Sub '${NASBackupBucket.Arn}/*' + Condition: + IpAddress: + 'aws:SourceIp': '${aws:PrincipalTag/cloudspout:fallback-ip}' - # Access Key for the NAS NASBackupUserAccessKey: Type: 'AWS::IAM::AccessKey' Properties: UserName: !Ref NASBackupUser + NASBackupSecret: + Type: 'AWS::SecretsManager::Secret' + Properties: + Name: !Sub 'nas-backup-credentials-${environment}' + SecretString: !Sub | + { + "AccessKeyId": "${NASBackupUserAccessKey}", + "SecretAccessKey": "${NASBackupUserAccessKey.SecretAccessKey}" + } + Tags: + - Key: 'cloudspout:environment' + Value: !Ref environment + - Key: 'cloudspout:project' + Value: 'nas-backup' + - Key: 'cloudspout:repository' + Value: 'cloudspout/nas-backup' + Outputs: BucketName: Value: !Ref NASBackupBucket - IAMUserName: - Value: !Ref NASBackupUser - AccessKeyId: - Value: !Ref NASBackupUserAccessKey - SecretAccessKey: - Value: !GetAtt NASBackupUserAccessKey.SecretAccessKey + SecretARN: + Value: !Ref NASBackupSecret From 3a9e93e89f9ba7f64476a259d5fc048f35748691 Mon Sep 17 00:00:00 2001 From: Sebastian Just Date: Sun, 22 Feb 2026 11:05:52 -0500 Subject: [PATCH 2/4] Linting --- .secrets.baseline | 150 ++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 1 - 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 .secrets.baseline diff --git a/.secrets.baseline b/.secrets.baseline new file mode 100644 index 0000000..7fd200f --- /dev/null +++ b/.secrets.baseline @@ -0,0 +1,150 @@ +{ + "version": "1.5.0", + "plugins_used": [ + { + "name": "ArtifactoryDetector" + }, + { + "name": "AWSKeyDetector" + }, + { + "name": "AzureStorageKeyDetector" + }, + { + "name": "Base64HighEntropyString", + "limit": 4.5 + }, + { + "name": "BasicAuthDetector" + }, + { + "name": "CloudantDetector" + }, + { + "name": "DiscordBotTokenDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "name": "GitLabTokenDetector" + }, + { + "name": "HexHighEntropyString", + "limit": 3.0 + }, + { + "name": "IbmCloudIamDetector" + }, + { + "name": "IbmCosHmacDetector" + }, + { + "name": "IPPublicDetector" + }, + { + "name": "JwtTokenDetector" + }, + { + "name": "KeywordDetector", + "keyword_exclude": "" + }, + { + "name": "MailchimpDetector" + }, + { + "name": "NpmDetector" + }, + { + "name": "OpenAIDetector" + }, + { + "name": "PrivateKeyDetector" + }, + { + "name": "PypiTokenDetector" + }, + { + "name": "SendGridDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "SoftlayerDetector" + }, + { + "name": "SquareOAuthDetector" + }, + { + "name": "StripeDetector" + }, + { + "name": "TelegramBotTokenDetector" + }, + { + "name": "TwilioKeyDetector" + } + ], + "filters_used": [ + { + "path": "detect_secrets.filters.allowlist.is_line_allowlisted" + }, + { + "path": "detect_secrets.filters.common.is_baseline_file", + "filename": ".secrets.baseline" + }, + { + "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", + "min_level": 2 + }, + { + "path": "detect_secrets.filters.heuristic.is_indirect_reference" + }, + { + "path": "detect_secrets.filters.heuristic.is_likely_id_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_lock_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_potential_uuid" + }, + { + "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign" + }, + { + "path": "detect_secrets.filters.heuristic.is_sequential_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_swagger_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_templated_secret" + } + ], + "results": { + "Makefile": [ + { + "type": "Secret Keyword", + "filename": "Makefile", + "hashed_secret": "504a5c3a2ce5fa0acc5f8d9685dc45860c25a8ed", + "is_verified": false, + "line_number": 16, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "Makefile", + "hashed_secret": "99c849bb78a99cb7d6c13e159d4f052f933efa49", + "is_verified": false, + "line_number": 17, + "is_secret": false + } + ] + }, + "generated_at": "2026-02-22T16:05:34Z" +} diff --git a/Makefile b/Makefile index 212352c..c2ba9a2 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,6 @@ install: - brew install tfenv brew install pre-commit gawk coreutils cfn-lint brew install checkov semgrep markdownlint-cli shellcheck pre-commit install From 4bffab21010c50a2ca41e2c8b45092a7976c55b5 Mon Sep 17 00:00:00 2001 From: Sebastian Just Date: Sun, 22 Feb 2026 11:12:23 -0500 Subject: [PATCH 3/4] fix --- infra/cfn/nas-backup.yml | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/infra/cfn/nas-backup.yml b/infra/cfn/nas-backup.yml index a1e4867..f69fa73 100644 --- a/infra/cfn/nas-backup.yml +++ b/infra/cfn/nas-backup.yml @@ -1,5 +1,5 @@ AWSTemplateFormatVersion: '2010-09-09' -Description: nas-backup stack with 3-block IAM policy for IP-restricted access. +Description: nas-backup stack - Corrected for IAM runtime variables and validation. Parameters: environment: @@ -37,7 +37,7 @@ Resources: - Key: 'cloudspout:repository' Value: 'cloudspout/nas-backup' - # IAM User with IP Tags + # IAM User NASBackupUser: Type: 'AWS::IAM::User' Properties: @@ -54,7 +54,7 @@ Resources: - Key: 'cloudspout:fallback-ip' Value: '0.0.0.0/0' - # IAM Managed Policy + # IAM Managed Policy - Using ${!} to escape IAM runtime variables NASBackupManagedPolicy: Type: 'AWS::IAM::ManagedPolicy' Properties: @@ -63,17 +63,17 @@ Resources: PolicyDocument: Version: '2012-10-17' Statement: - # BLOCK 1: Global Account Listing (IP Restricted) + # BLOCK 1: Global Account Listing - Effect: Allow Action: ['s3:ListAllMyBuckets'] Resource: '*' Condition: IpAddress: - 'aws:SourceIp': - - '${aws:PrincipalTag/cloudspout:home-ip}' - - '${aws:PrincipalTag/cloudspout:fallback-ip}' + 'aws:SourceIp': + - !Sub '${!aws:PrincipalTag/cloudspout:home-ip}' + - !Sub '${!aws:PrincipalTag/cloudspout:fallback-ip}' - # BLOCK 2: Bucket & Object Access via Home IP + # BLOCK 2: Home IP Access - Effect: Allow Action: - 's3:ListBucket' @@ -89,9 +89,9 @@ Resources: - !Sub '${NASBackupBucket.Arn}/*' Condition: IpAddress: - 'aws:SourceIp': '${aws:PrincipalTag/cloudspout:home-ip}' + 'aws:SourceIp': !Sub '${!aws:PrincipalTag/cloudspout:home-ip}' - # BLOCK 3: Bucket & Object Access via Fallback IP + # BLOCK 3: Fallback IP Access - Effect: Allow Action: - 's3:ListBucket' @@ -107,7 +107,7 @@ Resources: - !Sub '${NASBackupBucket.Arn}/*' Condition: IpAddress: - 'aws:SourceIp': '${aws:PrincipalTag/cloudspout:fallback-ip}' + 'aws:SourceIp': !Sub '${!aws:PrincipalTag/cloudspout:fallback-ip}' NASBackupUserAccessKey: Type: 'AWS::IAM::AccessKey' @@ -128,8 +128,6 @@ Resources: Value: !Ref environment - Key: 'cloudspout:project' Value: 'nas-backup' - - Key: 'cloudspout:repository' - Value: 'cloudspout/nas-backup' Outputs: BucketName: From 3c12796b84c9b4a755b4785d69715ca5a2d5c3d1 Mon Sep 17 00:00:00 2001 From: Sebastian Just Date: Sun, 22 Feb 2026 11:22:16 -0500 Subject: [PATCH 4/4] dasasdf --- infra/cfn/nas-backup.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/infra/cfn/nas-backup.yml b/infra/cfn/nas-backup.yml index f69fa73..d4ebf88 100644 --- a/infra/cfn/nas-backup.yml +++ b/infra/cfn/nas-backup.yml @@ -70,8 +70,14 @@ Resources: Condition: IpAddress: 'aws:SourceIp': - - !Sub '${!aws:PrincipalTag/cloudspout:home-ip}' - - !Sub '${!aws:PrincipalTag/cloudspout:fallback-ip}' + - '${aws:PrincipalTag/cloudspout:home-ip}' + - Effect: Allow + Action: ['s3:ListAllMyBuckets'] + Resource: '*' + Condition: + IpAddress: + 'aws:SourceIp': + - '${aws:PrincipalTag/cloudspout:fallback-ip}' # BLOCK 2: Home IP Access - Effect: Allow @@ -89,7 +95,7 @@ Resources: - !Sub '${NASBackupBucket.Arn}/*' Condition: IpAddress: - 'aws:SourceIp': !Sub '${!aws:PrincipalTag/cloudspout:home-ip}' + 'aws:SourceIp': '${aws:PrincipalTag/cloudspout:home-ip}' # BLOCK 3: Fallback IP Access - Effect: Allow @@ -107,7 +113,7 @@ Resources: - !Sub '${NASBackupBucket.Arn}/*' Condition: IpAddress: - 'aws:SourceIp': !Sub '${!aws:PrincipalTag/cloudspout:fallback-ip}' + 'aws:SourceIp': '${aws:PrincipalTag/cloudspout:fallback-ip}' NASBackupUserAccessKey: Type: 'AWS::IAM::AccessKey'