GD

My Cloud Journey

A working log: network security to AWS Azure GCP Cloud engineering

This page documents my hands-on path into cloud engineering: certifications earned, technologies touched, projects built, fails, frustrations, confusion, but definitely plenty of lessons learned along the way. It's a running record for myself, and everyone else, evaluating how I learn and build, not a polished highlight reel. So excuse the mess!

Entries

Project 1 - Update 2 - Static Site on S3 & CloudFront

Oof, this one was tough. I've used Github quite a lot before, but never the actions. I didn't want to use the access key route, I wanted to treat this more as a service account, something you would use in the business world. So I created the OIDC policy and permissions in AWS. I struggled with this for a while with Terraform not wanting to take what I had... Then of course there was the obligatory missing bracket that I had to hunt down and delete. Thankfully IDE's generally make that much easier these days. Eventually I actually created the OIDC via the GUI because at this point I can't wrap my head around how often they would be dynamically created via terraform, but I will research that later.

I moved on to creating the IAM Role, which proved easier, but still required research. One thing to be sure of though, I am still not quite certain what everything in these terraform scripts means. Resources are great to use, but as I'm getting started I'm still trying to learn all of these values. I can't get held up trying to be perfect and no it all or I will never make progress.

Terraform
data "aws_iam_openid_connect_provider" "github_actions" {
  url = "https://token.actions.githubusercontent.com"
}

data "aws_iam_policy_document" "github_actions_trust" {
  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRoleWithWebIdentity"]

    principals {
      type        = "Federated"
      identifiers = [data.aws_iam_openid_connect_provider.github_actions.arn]
    }

    condition {
      test     = "StringEquals"
      variable = "token.actions.githubusercontent.com:aud"
      values   = ["sts.amazonaws.com"]
    }

    condition {
      test     = "StringLike"
      variable = "token.actions.githubusercontent.com:sub"
      values   = ["repo:--My-Redacted-Account-Name@--My-Redacted-Account-ID/resume@--Redacted-Repo-ID:ref:refs/heads/main"]
    }
  }
}

resource "aws_iam_role" "github_actions_deploy" {
  name               = "github-actions-s3-deploy"
  assume_role_policy = data.aws_iam_policy_document.github_actions_trust.json
}

One issue I had here actually was that the documentation I found was incorrect, or outdated rather. Instead of just having my github account name and repository name, I also needed to include the IDs in them. I had to look through the Cloudtrail logs to find that AWS was expecting just the account name and repo name, but github was sending the names with the appended IDs. So that was definitely a learning experience I won't forget.

Finally I setup the permission policy to allow github to touch only this bucket. That actually turned out to be the easier of the things I learned today.
Terraform
data "aws_iam_policy_document" "github_actions_s3_deploy" {
  statement {
    sid       = "ListBucket"
    effect    = "Allow"
    actions   = ["s3:ListBucket"]
    resources = [aws_s3_bucket.bucketname.arn]
  }

  statement {
    sid       = "WriteObjects"
    effect    = "Allow"
    actions   = ["s3:PutObject", "s3:DeleteObject"]
    resources = ["${aws_s3_bucket.bucketname.arn}/*"]
  }
}

resource "aws_iam_role_policy" "github_actions_s3_deploy" {
  name   = "s3-deploy-policy"
  role   = aws_iam_role.github_actions_deploy.id
  policy = data.aws_iam_policy_document.github_actions_s3_deploy.json
}

output "github_actions_role_arn" {
  value = aws_iam_role.github_actions_deploy.arn
}

I feel like I have learned a lot. I'll need to review it more though so it sticks.

Project 1 - Update 1 - Static Site on S3 & CloudFront

This was my first solo adventure with terraform, so I wanted to keep it simple enough so that I could understand, but make it thorough enough to where I got something from it. Thankfully Hashicorp has great tutorial videos and documentation on their website for Terraform.

I built this script to build an AWS S3 bucket named main-resume-tf in my account (main resume bucket, terraform) and set the permissions on it to BucketOwnerEnforced, ensuring that any file uploaded to that bucket will be owned by me, the bucket owner. This goes without saying because I am the only one that will be uploading objects to that bucket, but it is good practice to be explicit.

Terraform
# Create an S3 bucket
resource "aws_s3_bucket" "main-tf" {
  bucket = "main-resume-tf"
}

# Set bucket ownership permissions
resource "aws_s3_bucket_ownership_controls" "main-tf" {
  bucket = aws_s3_bucket.main-tf.id
  rule {
    object_ownership = "BucketOwnerEnforced"
  }
}

I also wanted to have the objects in this bucket, at least some of them, be accessible from the public internet, as this is where I will be hosting my resume. So I wanted to change the ACL permissions, but I didn't want to leave it completely open, so I added the below script. I also decided not to do any versioning of this as it is such a simple bucket with only two files currently, but I did still want to look at how to version in terraform. I wrote out that script and commented it out.

Terraform
# Block some public access to this bucket. This bucket should be read
# only from the public internet for the resources defined later. Those
# resources will be index.html and cloud-journey.html.
#
resource "aws_s3_bucket_public_access_block" "data" {
  bucket = aws_s3_bucket.main-tf.id

  block_public_acls       = true
  block_public_policy     = false
  ignore_public_acls      = true
  restrict_public_buckets = false
}

# This code would enable versioning, but I actually don't want to for
# this simple setup. Versioning is essential in a business environment
# to track changes and be able to revert to previous working/proper
# versions when required.
# 
# resource "aws_s3_bucket_versioning" "versioning" {
#   bucket = aws_s3_bucket.main-tf.id
#   versioning_configuration {
#     status = "Enabled"
#   }
# }
#

  • Completed: Terraform module for S3 bucket creation and policy.
  • Remaining: Terraform modules for CloudFront distribution and Route 53
  • Remaining: GitHub Actions workflow for automated build and deploy on push
Project 1 - Static Site on S3 & CloudFront

Building and deploying a static website using Amazon S3 for storage, provisioned with Terraform and deployed via a GitHub Actions pipeline.

Goals: Infrastructure as code from the first commit, HTTPS via ACM, and a repeatable deploy process rather than manual console clicks.

  • Terraform modules for S3 bucket policy, CloudFront distribution, and Route 53
  • GitHub Actions workflow for automated build and deploy on push
Earned AWS Certified Cloud Practitioner

Passed the AWS Certified Cloud Practitioner exam, building a foundation across core AWS services, billing and pricing models, the shared responsibility model, and well-architected principles. This certification marks the formal start of a deliberate transition from enterprise network security toward cloud engineering.