Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: code for the lambda for exporting account tags #235

Merged
merged 7 commits into from
Mar 5, 2024

Conversation

CalvinRodo
Copy link
Member

@CalvinRodo CalvinRodo commented Mar 1, 2024

Summary

Add a Lambda function that extracts and writes the tag data for all accounts to an S3 bucket.
This function will be triggered once a day and the tag data will be used to enhance the billing
data being loaded into Superset.

@patheard patheard self-assigned this Mar 1, 2024
@patheard
Copy link
Member

patheard commented Mar 1, 2024

Add the Terraform and GitHub workflow updates to manage
the Lambda function.

Add unit tests for the Lambda function code.
@patheard patheard marked this pull request as ready for review March 5, 2024 15:05
@patheard patheard requested a review from a team March 5, 2024 15:10
Copy link

github-actions bot commented Mar 5, 2024

Plan for org_account/billing_extract_tags

✅   Terraform Init: success
✅   Terraform Validate: success
✅   Terraform Format: success
✅   Terraform Plan: success
✅   Conftest: success

Plan: 3 to import, 10 to add, 2 to change, 0 to destroy
Show summary
CHANGE NAME
add aws_cloudwatch_event_rule.billing_extract_tags
aws_cloudwatch_event_target.billing_extract_tags
aws_cloudwatch_log_group.billing_extract_tags
aws_iam_policy.billing_extract_tags
aws_iam_role.billing_extract_tags
aws_iam_role_policy_attachment.billing_extract_tags
aws_iam_role_policy_attachment.lambda_insights
aws_iam_role_policy_attachment.org_read_only
aws_lambda_function.billing_extract_tags
aws_lambda_permission.billing_extract_tags
update aws_s3_bucket_policy.billing_extract_tags
module.billing_extract_tags.aws_s3_bucket.this
Show plan
Resource actions are indicated with the following symbols:
  + create
  ~ update in-place
 <= read (data resources)

Terraform will perform the following actions:

  # data.aws_iam_policy_document.billing_extract_tags_bucket will be read during apply
  # (config refers to values not yet known)
 <= data "aws_iam_policy_document" "billing_extract_tags_bucket" {
      + id   = (known after apply)
      + json = (known after apply)

      + statement {
          + actions   = [
              + "s3:DeleteObject*",
              + "s3:GetBucketLocation",
              + "s3:GetObject*",
              + "s3:ListBucket",
              + "s3:PutObject*",
            ]
          + effect    = "Allow"
          + resources = [
              + "arn:aws:s3:::5bf89a78-1503-4e02-9621-3ac658f558fb",
              + "arn:aws:s3:::5bf89a78-1503-4e02-9621-3ac658f558fb/*",
            ]

          + principals {
              + identifiers = [
                  + (known after apply),
                ]
              + type        = "AWS"
            }
        }
      + statement {
          + actions   = [
              + "s3:AbortMultipartUpload",
              + "s3:GetBucketLocation",
              + "s3:GetObject",
              + "s3:ListBucket",
              + "s3:ListBucketMultipartUploads",
              + "s3:ListMultipartUploadParts",
            ]
          + effect    = "Allow"
          + resources = [
              + "arn:aws:s3:::5bf89a78-1503-4e02-9621-3ac658f558fb",
              + "arn:aws:s3:::5bf89a78-1503-4e02-9621-3ac658f558fb/*",
            ]

          + principals {
              + identifiers = [
                  + "arn:aws:iam::066023111852:root",
                ]
              + type        = "AWS"
            }
        }
    }

  # aws_cloudwatch_event_rule.billing_extract_tags will be created
  + resource "aws_cloudwatch_event_rule" "billing_extract_tags" {
      + arn                 = (known after apply)
      + event_bus_name      = "default"
      + id                  = (known after apply)
      + is_enabled          = true
      + name                = "billing_extract_tags_daily"
      + name_prefix         = (known after apply)
      + schedule_expression = "cron(0 5 * * ? *)"
      + tags                = {
          + "CostCentre" = "cds-aws-lz-production"
          + "Terraform"  = "true"
        }
      + tags_all            = {
          + "CostCentre" = "cds-aws-lz-production"
          + "Terraform"  = "true"
        }
    }

  # aws_cloudwatch_event_target.billing_extract_tags will be created
  + resource "aws_cloudwatch_event_target" "billing_extract_tags" {
      + arn            = (known after apply)
      + event_bus_name = "default"
      + id             = (known after apply)
      + rule           = "billing_extract_tags_daily"
      + target_id      = (known after apply)
    }

  # aws_cloudwatch_log_group.billing_extract_tags will be created
  + resource "aws_cloudwatch_log_group" "billing_extract_tags" {
      + arn               = (known after apply)
      + id                = (known after apply)
      + name              = "/aws/lambda/billing_extract_tags"
      + name_prefix       = (known after apply)
      + retention_in_days = 14
      + skip_destroy      = false
      + tags              = {
          + "CostCentre" = "cds-aws-lz-production"
          + "Terraform"  = "true"
        }
      + tags_all          = {
          + "CostCentre" = "cds-aws-lz-production"
          + "Terraform"  = "true"
        }
    }

  # aws_iam_policy.billing_extract_tags will be created
  + resource "aws_iam_policy" "billing_extract_tags" {
      + arn         = (known after apply)
      + id          = (known after apply)
      + name        = "BillingExtractTags"
      + name_prefix = (known after apply)
      + path        = "/"
      + policy      = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = "logs:CreateLogGroup"
                      + Effect   = "Allow"
                      + Resource = "arn:aws:logs:ca-central-1:659087519042:*"
                    },
                  + {
                      + Action   = [
                          + "logs:PutLogEvents",
                          + "logs:CreateLogStream",
                        ]
                      + Effect   = "Allow"
                      + Resource = "arn:aws:logs:ca-central-1:659087519042:log-group:/aws/lambda/billing_extract_tags:*"
                    },
                  + {
                      + Action   = [
                          + "s3:PutObject*",
                          + "s3:ListBucket",
                          + "s3:GetObject*",
                          + "s3:GetBucketLocation",
                          + "s3:DeleteObject*",
                        ]
                      + Effect   = "Allow"
                      + Resource = [
                          + "arn:aws:s3:::5bf89a78-1503-4e02-9621-3ac658f558fb/*",
                          + "arn:aws:s3:::5bf89a78-1503-4e02-9621-3ac658f558fb",
                        ]
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + policy_id   = (known after apply)
      + tags        = {
          + "CostCentre" = "cds-aws-lz-production"
          + "Terraform"  = "true"
        }
      + tags_all    = {
          + "CostCentre" = "cds-aws-lz-production"
          + "Terraform"  = "true"
        }
    }

  # aws_iam_role.billing_extract_tags will be created
  + resource "aws_iam_role" "billing_extract_tags" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "lambda.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "BillingExtractTags"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags                  = {
          + "CostCentre" = "cds-aws-lz-production"
          + "Terraform"  = "true"
        }
      + tags_all              = {
          + "CostCentre" = "cds-aws-lz-production"
          + "Terraform"  = "true"
        }
      + unique_id             = (known after apply)
    }

  # aws_iam_role_policy_attachment.billing_extract_tags will be created
  + resource "aws_iam_role_policy_attachment" "billing_extract_tags" {
      + id         = (known after apply)
      + policy_arn = (known after apply)
      + role       = "BillingExtractTags"
    }

  # aws_iam_role_policy_attachment.lambda_insights will be created
  + resource "aws_iam_role_policy_attachment" "lambda_insights" {
      + id         = (known after apply)
      + policy_arn = "arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy"
      + role       = "BillingExtractTags"
    }

  # aws_iam_role_policy_attachment.org_read_only will be created
  + resource "aws_iam_role_policy_attachment" "org_read_only" {
      + id         = (known after apply)
      + policy_arn = "arn:aws:iam::aws:policy/AWSOrganizationsReadOnlyAccess"
      + role       = "BillingExtractTags"
    }

  # aws_lambda_function.billing_extract_tags will be created
  + resource "aws_lambda_function" "billing_extract_tags" {
      + architectures                  = (known after apply)
      + arn                            = (known after apply)
      + filename                       = "/tmp/main.py.zip"
      + function_name                  = "billing_extract_tags"
      + handler                        = "main.handler"
      + id                             = (known after apply)
      + invoke_arn                     = (known after apply)
      + last_modified                  = (known after apply)
      + memory_size                    = 1024
      + package_type                   = "Zip"
      + publish                        = false
      + qualified_arn                  = (known after apply)
      + qualified_invoke_arn           = (known after apply)
      + reserved_concurrent_executions = -1
      + role                           = (known after apply)
      + runtime                        = "python3.11"
      + signing_job_arn                = (known after apply)
      + signing_profile_version_arn    = (known after apply)
      + skip_destroy                   = false
      + source_code_hash               = "oKdEO6vgvvXn6bgDgo940IkMbjRRglD6jt7rCLrRcjI="
      + source_code_size               = (known after apply)
      + tags                           = {
          + "CostCentre" = "cds-aws-lz-production"
          + "Terraform"  = "true"
        }
      + tags_all                       = {
          + "CostCentre" = "cds-aws-lz-production"
          + "Terraform"  = "true"
        }
      + timeout                        = 30
      + version                        = (known after apply)

      + environment {
          + variables = {
              + "TARGET_BUCKET" = "5bf89a78-1503-4e02-9621-3ac658f558fb"
            }
        }

      + tracing_config {
          + mode = "PassThrough"
        }
    }

  # aws_lambda_permission.billing_extract_tags will be created
  + resource "aws_lambda_permission" "billing_extract_tags" {
      + action              = "lambda:InvokeFunction"
      + function_name       = "billing_extract_tags"
      + id                  = (known after apply)
      + principal           = "events.amazonaws.com"
      + source_arn          = (known after apply)
      + statement_id        = "AllowBillingExtractTagsDaily"
      + statement_id_prefix = (known after apply)
    }

  # aws_s3_bucket_policy.billing_extract_tags will be updated in-place
  # (imported from "5bf89a78-1503-4e02-9621-3ac658f558fb")
  ~ resource "aws_s3_bucket_policy" "billing_extract_tags" {
        bucket = "5bf89a78-1503-4e02-9621-3ac658f558fb"
        id     = "5bf89a78-1503-4e02-9621-3ac658f558fb"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "s3:GetBucketLocation",
                          - "s3:GetObject",
                          - "s3:ListBucket",
                          - "s3:ListBucketMultipartUploads",
                          - "s3:ListMultipartUploadParts",
                          - "s3:AbortMultipartUpload",
                        ]
                      - Effect    = "Allow"
                      - Principal = {
                          - AWS = "arn:aws:iam::066023111852:root"
                        }
                      - Resource  = [
                          - "arn:aws:s3:::5bf89a78-1503-4e02-9621-3ac658f558fb",
                          - "arn:aws:s3:::5bf89a78-1503-4e02-9621-3ac658f558fb/*",
                        ]
                      - Sid       = "CDSSupersetRootRead"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
    }

  # module.billing_extract_tags.aws_s3_bucket.this will be updated in-place
  # (imported from "5bf89a78-1503-4e02-9621-3ac658f558fb")
  ~ resource "aws_s3_bucket" "this" {
      + acl                         = "private"
        arn                         = "arn:aws:s3:::5bf89a78-1503-4e02-9621-3ac658f558fb"
        bucket                      = "5bf89a78-1503-4e02-9621-3ac658f558fb"
        bucket_domain_name          = "5bf89a78-1503-4e02-9621-3ac658f558fb.s3.amazonaws.com"
        bucket_regional_domain_name = "5bf89a78-1503-4e02-9621-3ac658f558fb.s3.ca-central-1.amazonaws.com"
      + force_destroy               = false
        hosted_zone_id              = "Z1QDHH18159H29"
        id                          = "5bf89a78-1503-4e02-9621-3ac658f558fb"
        object_lock_enabled         = false
        policy                      = jsonencode(
            {
                Statement = [
                    {
                        Action    = [
                            "s3:GetBucketLocation",
                            "s3:GetObject",
                            "s3:ListBucket",
                            "s3:ListBucketMultipartUploads",
                            "s3:ListMultipartUploadParts",
                            "s3:AbortMultipartUpload",
                        ]
                        Effect    = "Allow"
                        Principal = {
                            AWS = "arn:aws:iam::066023111852:root"
                        }
                        Resource  = [
                            "arn:aws:s3:::5bf89a78-1503-4e02-9621-3ac658f558fb",
                            "arn:aws:s3:::5bf89a78-1503-4e02-9621-3ac658f558fb/*",
                        ]
                        Sid       = "CDSSupersetRootRead"
                    },
                ]
                Version   = "2012-10-17"
            }
        )
        region                      = "ca-central-1"
        request_payer               = "BucketOwner"
      ~ tags                        = {
          + "CostCentre" = "cds-aws-lz-production"
          + "Critical"   = "false"
          ~ "Terraform"  = "false" -> "true"
        }
      ~ tags_all                    = {
          + "CostCentre" = "cds-aws-lz-production"
          + "Critical"   = "false"
          ~ "Terraform"  = "false" -> "true"
        }

        grant {
            id          = "25b295e1922069b04c7a73186f3a08bead60b7565ffee84d635391167d484fa0"
            permissions = [
                "FULL_CONTROL",
            ]
            type        = "CanonicalUser"
        }

      ~ server_side_encryption_configuration {
          ~ rule {
              ~ bucket_key_enabled = true -> false

                apply_server_side_encryption_by_default {
                    sse_algorithm = "AES256"
                }
            }
        }

      ~ versioning {
          ~ enabled    = false -> true
            mfa_delete = false
        }
    }

  # module.billing_extract_tags.aws_s3_bucket_public_access_block.this will be imported
    resource "aws_s3_bucket_public_access_block" "this" {
        block_public_acls       = true
        block_public_policy     = true
        bucket                  = "5bf89a78-1503-4e02-9621-3ac658f558fb"
        id                      = "5bf89a78-1503-4e02-9621-3ac658f558fb"
        ignore_public_acls      = true
        restrict_public_buckets = true
    }

Plan: 3 to import, 10 to add, 2 to change, 0 to destroy.

Warning: Argument is deprecated

  with module.billing_extract_tags.aws_s3_bucket.this,
  on .terraform/modules/billing_extract_tags/S3/main.tf line 8, in resource "aws_s3_bucket" "this":
   8: resource "aws_s3_bucket" "this" {

Use the aws_s3_bucket_versioning resource instead

(and 3 more similar warnings elsewhere)

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: plan.tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "plan.tfplan"
Show Conftest results
20 tests, 20 passed, 0 warnings, 0 failures, 0 exceptions

@patheard patheard merged commit de58a2e into main Mar 5, 2024
15 checks passed
@patheard patheard deleted the feat/tag_lambda_export branch March 5, 2024 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants