From 'Permission Denied' to Production: My AWS & Terraform Journey

Published: (December 30, 2025 at 09:58 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

Cover image for From “Permission Denied” to Production: My AWS & Terraform Journey

Zakariyau Mukhtar

The Pivot From DigitalOcean to AWS

I was following a course that used DigitalOcean to deploy the Java app. DigitalOcean kept rejecting my cards because I’m in Nigeria, so I hit a brick wall.

Instead of giving up, I remembered my #30ofAWSTerraform challenge. AWS is more complex, but it’s the industry leader. I decided to translate the DigitalOcean “Firewall” into an AWS Security Group and gain real‑world experience.

1. Provisioning Infrastructure with Terraform

My goal was to use Infrastructure as Code (IaC) to create an EC2 instance. I used the aws_instance and aws_key_pair resources.

The Challenge: SSH Key Management

Passing the public key as a raw string variable caused formatting errors.

The Solution

Use Terraform’s file() function to read the public key directly from disk, ensuring the exact bytes on my Windows machine are sent to AWS.

resource "aws_key_pair" "my_ssh_key" {
  key_name   = "zacks-key"
  public_key = file("C:/Users/Public/id_aws.pub")
}

Terraform Code Samples

Main.tf – Terraform code block

Main.tf – Additional code block

2. The Battle of AMI IDs and Usernames

Even after the instance was “running,” I couldn’t SSH in. I kept seeing InvalidAMIID.NotFound or Permission denied (publickey).

Lessons Learned

IssueWhat I Learned
Region SpecificityAMI IDs are region‑specific. An Ubuntu AMI for London won’t work in North Virginia (us-east-1).
Architecture Matterst2.micro requires an x86_64 image. Using an ARM‑based AMI results in a “Not Found” error.
Default UserEach OS has its own default SSH user: ec2-user for Amazon Linux, ubuntu for Ubuntu, etc.

3. Deploying the Application (The JAR File)

Once I could SSH into the server, I needed to copy my Java artifact from build/libs to the EC2 instance.

The Tool: SCP (Secure Copy)

scp -i C:\Users\Public\id_aws "C:\Users\...\java-app-1.0-SNAPSHOT.jar" ubuntu@:/home/ubuntu/

Build Successful

Translating Firewall to Security Group

When the instructor added a firewall rule on DigitalOcean, I mirrored it in AWS by updating the Security Group in Terraform to open Port 8080, allowing traffic to reach my Spring Boot app.

4. Linux User Management & Security

For better security, I created a personal user zacks.

Steps Taken

  1. Create the user

    sudo adduser zacks
  2. Grant sudo privileges

    sudo usermod -aG sudo zacks
  3. Fix SSH authorized keys
    I mistakenly named the key file Authentication_keys. Linux expects authorized_keys. I also corrected ownership and permissions:

    sudo mv /home/zacks/.ssh/Authentication_keys /home/zacks/.ssh/authorized_keys
    sudo chown -R zacks:zacks /home/zacks/.ssh
    sudo chmod 600 /home/zacks/.ssh/authorized_keys

Conclusion

Today was a masterclass in troubleshooting. I learned that DevOps isn’t just about writing code; it’s about being adaptable. When one cloud door closed, I used Terraform to open a better one on AWS.

Java Application started on server (image placeholder – replace with the actual URL)

Infrastructure Diagram

Infrastructure is live, the JAR is running, and the “Whitelabel Error Page” never looked so beautiful!

Application Page

Back to Blog

Related posts

Read more »