Step-by-Step Guidance

Welcome to the Step-by-Step Guidance version of this project. Let's do this!

Want a complete demo of how to do this project, from start to finish? Check out our ๐ŸŽฌ walkthrough with Natasha ๐ŸŽฌ

๐Ÿ“ฃ If you're EVER stuck - ask the NextWork community. Students like you are already asking questions about this project.

In this project, we're going to learn how to use AWS Secrets Manager to securely store and retrieve secrets.

Imagine that you're about to build a web app that displays the names of the S3 buckets under your account. Now, for the web app to showcase your S3 buckets, it's gonna need AWS credentials. How should your web app get those credentials?

The first thing that might come to mind is to store the credentials in the web app's code itself. This is what your web app is going to do initially... but as you'll find out, this is not the greatest idea ๐Ÿ™ˆ

When credentials are hardcoded into your code, they can be easily accessed by anyone who has access to your code. And sharing code happens all the time - especially when you decide to showcase your project publicly in a GitHub portfolio!

This is why it's important to store credentials in a secure way. We're going to learn about a better way to store and retrieve these credentials using AWS Secrets Manager.


How in the world do we update an insecure web app to use AWS Secrets Manager?

In this step, we'll take a look at a simple web app that lists S3 buckets, copy the code to our computer, and set it up to hardcode some AWS credentials ๐Ÿ˜ฌ


In this step, you're going to:

Access and Explore the Repository

๐Ÿ’ก What is GitHub?
GitHub is a platform where developers share and collaborate on code. It's like a social media for code!

Public repositories on GitHub are great for open-source projects, but it also means that anyone can see the code. This is why it's super important to never put sensitive information, like passwords or AWS credentials, directly into your code, especially if it's in a public repository!


Understand the Application Code

๐Ÿ’ก What is app.py?
app.py is the main file containing the logic of our web app i.e. how the app will respond to user requests and interact with AWS services. In our case, app.py contains all the code that connects to your AWS account and lists the names of your S3 buckets.


๐Ÿ’ก Extra for Experts: How is app.py built?
app.py is built using FastAPI, a web framework for building APIs with Python. Think of it as a set of tools and rules that make it easier to build web apps that can talk to each other over the internet.

FastAPI helps developers like us create APIs quickly and efficiently, with features like automatic data validation and interactive documentation.

Let's explore app.py and understand how it works!

๐Ÿ’ก What are import statements?
Import statements bring in external code libraries that our application needs to work. These libraries provide pre-built functionality so we don't have to write everything from scratch.

๐Ÿ’ก What does import config do?
This line tells app.py to load settings from another file named config.py. We'll check out config.py soon to see what kind of settings it holds.


Examine config.py

๐Ÿ’ก What is config.py?
config.py is a file that contains the configuration settings for our web app. Think of it as your app's settings file.

In our case, config.py contains the AWS credentials for our web app - AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION. Without these credentials, app.py wouldn't be able to connect to your AWS account.


The Security Risks...

Notice how the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are directly written in config.py. If this were a real, public application, and you shared the code on a GitHub repository, anyone could see these credentials! ๐Ÿ˜ฑ

Exposing your AWS credentials publicly is a major security risk and is extremely unsafe for production applications. Once someone else gets access to your credentials, they can use them to access your AWS account, delete resources, steal data, and cause damage.

It's not just AWS credentials; database passwords, API keys for other services, and any kind of secret should never be directly embedded in your code.

To make this web app more secure, we'll make a copy of it in our local computer, and then we'll play around with how config.py stores credentials in our copy.


Set Up Your Local Environment

We'll be using the terminal to make a copy of the GitHub repository's code:

  • Open Terminal. You can find it by searching in Spotlight (press Cmd + Space and type "Terminal") or in your applications menu.

๐Ÿ’ก What is a terminal?
A terminal is where you can interact with your computer (e.g. download files, run programs, install tools, etc.) using text commands. It's like you're telling your computer what to do in a chat, except you're using special commands instead of words!

From your terminal, let's head to your Documents folder, a common place to store project files. We'll clone the repository there.

  • In your terminal, type cd Documents and press Enter.

  • Open Command Prompt. You can find it by searching for "Command Prompt" in the Start menu.

๐Ÿ’ก What is a terminal?
A terminal is where you can interact with your computer (e.g. download files, run programs, install tools, etc.) using text commands. It's like you're telling your computer what to do in a chat, except you're using special commands instead of words!

From your Command Prompt, let's head to your Documents folder, a common place to store project files. We'll clone the repository there.

  • In your Command Prompt, type cd Documents and press Enter.


Clone the GitHub Repository

Now we'll clone the GitHub repository to your local machine. Cloning copies all the files from the GitHub repository to a new folder in your computer.

git clone [HTTPS-URL]

๐Ÿ™‹โ€โ™€๏ธ Where do I find the HTTPS-URL?
You can find the HTTPS-URL by heading back to the GitHub repository and clicking the green Code button.

๐Ÿ™‹โ€โ™€๏ธ Getting a 'Git not found' error?
That's totally okay! This just means you don't have Git installed on your computer.

  • Head over to git-scm.com/downloads.
  • Download and run the installer for your operating system.
  • Once installed, restart your IDE and try again.

Still having issues? Troubleshoot here or share your error with the NextWork community!


Let's double-check that we're in the correct folder:

  • Type pwd and press Enter to see your current directory.

  • You should see the path to the nextwork-security-secretsmanager directory printed in your terminal.
  • Type ls and press Enter to list the files in your directory.
  • You should see files like app.py, config.py, Dockerfile, and requirements.txt. Yup, these are the same files we saw in the GitHub repository!

๐Ÿ’ก Extra for Experts: What do these files do?

  • Dockerfile: Used for building the Docker image for the application - if you were to deploy this app, you would use this file to deploy it to container services like AWS ECR, Elastic Beanstalk or ECS.
  • app.py: The main application file, containing the FastAPI code that defines the web app.
  • config.py: Contains AWS credentials (currently hardcoded - this is what we'll fix!).
  • index.html: The landing page for the web app, a simple HTML file.
  • requirements.txt: Lists the Python libraries required by the application.
  • static: Folder containing static files (like CSS) for the web app's styling.
  • Open config.py in a text editor. You can use nano config.
  • Type cd and press Enter to see your current directory.
  • You should see the path to the nextwork-security-secretsmanager directory printed in your terminal.
  • Type dir and press Enter to list the files in your directory.
  • You should see files like app.py, config.py, Dockerfile, and requirements.txt. Yup, these are the same files we saw in the GitHub repository!

๐Ÿ’ก Extra for Experts: What do these files do?

  • Dockerfile: Used for building the Docker image for the application - if you were to deploy this app, you would use this file to deploy it to container services like AWS ECR, Elastic Beanstalk or ECS.
  • app.py: The main application file, containing the FastAPI code that defines the web app.
  • config.py: Contains AWS credentials (currently hardcoded - this is what we'll fix!).
  • index.html: The landing page for the web app, a simple HTML file.
  • requirements.txt: Lists the Python libraries required by the application.
  • static: Folder containing static files (like CSS) for the web app's styling.
  • Open config.py in a text editor. You can use notepad config.
AWS_ACCESS_KEY_ID = "AKIAW3MEFRAFTQM5FHKE" AWS_SECRET_ACCESS_KEY = "F0b8s5m+pOZsttvBCirr1BOutuvCpqXMW2Y1qAxY" AWS_REGION = "us-east-2"

๐Ÿ’ก What are these credentials?
These are example access keys for AWS - we're going to imagine that these are real AWS credentials that would give someone access to your AWS account!

We're using these test credentials as it's easier and safer to use than real credentials that would expose your account to security risks. Because these credentials are fake, putting them in config.py won't actually let your web app work (you won't see this web app display your S3 buckets' names).


๐Ÿ’ก What are AWS access keys?
AWS access keys are like a username (Access Key ID) and password (Secret Access Key) that let applications to access your AWS account programmatically. When an application uses these keys, AWS treats the requests (e.g. creating or deleting resources, accessing data) as if they're coming directly from you.

This is why securing your access keys is critical - if someone gets hold of them, they could use all your AWS services with your credentials, potentially racking up large bills or accessing sensitive data in your account.


๐Ÿ™‹โ€โ™€๏ธ Noooooo, I wanted to see the web app work!
If you want to see the web app work, you'll need to create your own AWS credentials and put them in config.py. Wanna do this? You can!

We'll show you how to in the ๐Ÿ’Ž Secret Mission below.

  • Press Ctrl+O to save your changes.
  • Press Enter to confirm.
  • Press Ctrl+X to exit nano.
  • Press Ctrl+S to save the file
  • Close Notepad

Want to see this app in action? Here's your chance!

Let's put some skin in the game... your mission, should you choose to accept it, is to run this web app using your very own AWS credentials.

By doing this secret mission, you'll also get first-hand experience on why we need to secure our credentials. Later in this project, you'll need to take extra care that the real credentials you put in here don't get exposed publicly!


In this step, you're going to:

Sweet! Our web app now has AWS credentials to get it to work. But here's where things get interesting - we've got our credentials sitting right there in our code, and that's... well, not great ๐Ÿ˜…

Let's see what happens when we try to share this code on GitHub. To do this, we'll fork the original repository (i.e. make our own copy that's stored in GitHub), and then push our hardcoded credentials to the forked repository.


In this step, you're going to:

Woooo exciting - let's get you set up! Signing up is free and takes just 5 minutes.

๐Ÿ’ก What is Github?
GitHub is a place for engineers to store and share their code and projects online. It's called GitHub because it uses Git to manage your projects' version history.

  • Follow the prompts to create your account by entering your email, creating a password, and choosing a username.

  • Complete one of their bot verification tasks. Switch the task type to Audio if the Visual task crashes your website.
  • Once your account is created, confirm your email address with a verification code sent to your inbox.

  • Log into your GitHub account once you've verified your email.

  • Welcome to your GitHub account!

Fork the Web App Code on GitHub

๐Ÿ’ก What is a fork (in GitHub)?
Forking a repository on GitHub is like making a personal copy of an existing repository, and editing and storing that copy in your own GitHub account. This is a great option if you'd like to showcase your version of the web app, and make changes to it without affecting the original repository.


๐Ÿ’ก What is forking vs. cloning?
When you fork a repository, you're making a copy of it in your GitHub account online. If your forked repository is public, anyone can see it!

  • When you clone a repository, you're creating a local, offline copy. By default, no one can see it since it's stored on your computer.

Push Your Code to GitHub

Nice! With your forked repository available, you can now push your version of the web app. Let's make it public! We'll get back to our terminal to connect our edited code to the forked repository.

In case you haven't already, let's initialize Git in your local project directory. This tells Git to track the changes you make to the code.

Now, we need to connect your local repository to your forked repository on GitHub. To do this, we'll add a remote named "origin" that points to your fork's URL.

๐Ÿ’ก What is a remote in Git?
A remote is like an address book entry in Git that tells it where your code lives online. Instead of remembering the full URL every time, Git lets you give each location a nickname. In our case, we'll call it "origin" and it points to the URL of our forked repository on GitHub.

P.S. You can actually name your saved URL anything, but "origin" is the standard that most developers use.

git remote add origin <your-forked-repo-url>

git remote set-url origin <your-forked-repo-url>

๐Ÿ’ก What does this command do?
This command uploads your local commits to your "origin" remote. The -u and main tells Git to set make the main branch the upstream branch, so next time you push code, you can just run git push and it'll automatically know where to push the code.

GitHub's Secret Scanning Block


Uh oh! You probably see an error message saying "Push cannot contain secrets". GitHub automatically scans your code for secrets and blocks the push if it detects any, like AWS credentials.

In our case, GitHub detected that you are trying to push code that contains an AWS Access Key ID and Secret Access Key in config.py. This is a great security feature from GitHub to prevent accidental exposure of secrets!

Man, GitHub is so smart ๐Ÿ˜ฎโ€๐Ÿ’จ

Running into this error highlights the exact problem we're trying to solve in this project: how do you manage secrets securely so they're not exposed in your code? In this case, it's even stopped us from sharing our code publicly!

This is where AWS Secrets Manager comes in! In the next step, we'll learn how to use Secrets Manager to store your AWS credentials securely, plus retrieve them in your application without hardcoding them in config.py.

So, GitHub rightly blocked us from pushing our code with hardcoded credentials. This highlights exactly why we need a secure way to manage secrets! The solution is to use a dedicated service for managing secrets securely - AWS Secrets Manager.

In this step, we're going to use AWS Secrets Manager to store your AWS credentials securely. We'll create a new secret in Secrets Manager, and then update your config.py file to retrieve these credentials from Secrets Manager instead of hardcoding them.


In this step, you're going to:

๐Ÿ’ก What is AWS Secrets Manager?
AWS Secrets Manager is a service that helps you securely store and manage secrets, such as database credentials, API keys, and other sensitive information. Think of it as a digital vault for your secrets.

Secrets Manager encrypts your secrets and allows you to retrieve them programmatically in your applications, without hardcoding them in your code. It also offers features like secret rotation and auditing to further enhance security.


Why use Secrets Manager?

  • Security: Secrets are encrypted at rest and in transit, and access is controlled through IAM policies.
  • Centralized management: Manage all your secrets in one place.
  • Rotation: Automate secret rotation to improve security posture.
  • Auditing: Track access to secrets for compliance and security monitoring.

Now let's create a new secret to securely store our AWS credentials.

What types of secrets can Secrets Manager store?
Secrets Manager can store various types of secrets, including:

  • Database credentials: Usernames and passwords for databases like MySQL, PostgreSQL, SQL Server, etc.
  • API keys: API keys for accessing third-party services.
  • OAuth tokens: Tokens for authentication and authorization.
  • Any other sensitive information: You can store any text-based secret in Secrets Manager.

๐Ÿ’ก What is Encryption?
Encryption is like scrambling a message so that only someone with the right key can unscramble it and read it. In our case, Secrets Manager uses an encryption key to encrypt your secrets, so the access key ID and secret access key are scrambled and cannot be read by anyone without the right access.


What is AWS KMS?
AWS Key Management Service (KMS) is a service that helps you create and manage encryption keys securely in AWS. Secrets Manager uses KMS to encrypt your secrets, ensuring that they are protected at rest. You can also learn more in our project on using AWS KMS!

Now, we need to give our secret a name and description.

๐Ÿ’ก What do these optional settings do?

  • Tags can help you organize and manage your secrets.
  • Resource permissions allow you to control who and what can access this secret.
  • Replicate secret allows you to replicate this secret to other AWS regions for disaster recovery and lower latency access from those regions.

๐Ÿ’ก What is Secret Rotation?
Secret rotation is the process of automatically changing your secrets on a regular schedule. This is a security best practice because it reduces the risk of compromised credentials. If a secret is compromised, it will only be valid for a limited time before it's automatically rotated.

Secrets Manager can automatically rotate secrets for databases and other services. You can also configure custom rotation for other types of secrets.


๐Ÿ’ก When should you use secret rotation?
Secret rotation is best for high-risk credentials like database passwords, privileged API keys, and service account credentials. These types of secrets, if compromised, could give attackers access to sensitive data or critical systems, so regular rotation helps limit the damage window.

However, you might want to skip rotation for keys (where automated rotation isn't supported), hardware security tokens, or legacy systems that can't handle credential updates without downtime.

Secret type: Other type of secret

Encryption key: aws/secretsmanager

Secret name: aws-access-key

Description: Created to replace hard-coded access key credentials in config.py

Secret replication: Disabled

Automatic rotation: Disabled

Alright, now comes the fun part! ๐ŸŽจ We're going to transform our config.py file from a security risk into a secure, professional piece of code. Instead of having our AWS credentials just sitting there in plain text (yikes!), we'll use the sample code from Secrets Manager to fetch them securely.


In this step, you're going to:

Grab the Sample Code

Now we'll update our config.py file to use Secrets Manager instead of hardcoded credentials.

It's easier to do this in a code editor (like VS Code) instead of directly in the terminal, but the choice is yours!

  • Open VS Code or your preferred code editor.
  • Navigate to your project directory and open config.py

  • In config.py, replace the entire file with the code snippet you copied from Secrets Manager.
  • Delete the comment line # Your code goes here from the get_secret() function.

Let's delete the old config.py file and create a new one with our secure code! The instructions for this depends on your operating system:

  • In your terminal, let's first delete the existing config.py file:
rm config.py
  • Now, let's create a new config.py file using nano:
nano config.py
  • In your new empty file, paste the Python code from Secrets Manager (don't forget to find this code in your Secrets Manager console).
  • Delete the existing config.py file:
del config.py
  • Create a new config.py file:
type nul > config.py
  • Open the new file in Notepad:
notepad config.py
  • In the empty Notepad window, paste the Python code from Secrets Manager (don't forget to find this code in your Secrets Manager console).

Let's get to know our brand new config.py file ๐Ÿ•ต

The first two lines are import statements:


The core of the pasted code is the get_secret() function:

๐Ÿ’ก Why are we adding new lines to the code?
Great question! So far, the code provided by Secrets Manager only help us with creating a function for retrieving the secret. But, config.py still has one more job left to do - it needs to retrieve the secret from the function we create (get_secret()) and assign the values to the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION variables that our app.py code expects.

Now let's add the code to use the get_secret() function and retrieve our credentials:

  • Open config.py in your code editor if it's not already open.
  • Add the following code block at the end of the file:
return json.loads(secret) # Retrieve credentials from Secrets Manager credentials = get_secret() # Extract the values; if AWS_REGION isn't in the secret, use the region from the session AWS_ACCESS_KEY_ID = credentials.get("AWS_ACCESS_KEY_ID") AWS_SECRET_ACCESS_KEY = credentials.get("AWS_SECRET_ACCESS_KEY") AWS_REGION = credentials.get("AWS_REGION", boto3.session.Session().region_name or "us-east-2")

  • Since this piece of code uses a new package json, we need to import it at the top of the file. Add the following line to your import statements:
import json

  • Save the updated config.py file in your code editor.
  • If you've closed the file, open config.py again using nano config.py

  • Use the down arrow to go to the end of the file.

  • Delete the placeholder comment line # Your code goes here (use Ctrl+K to delete a line)

  • Add the following code block: ```python return json.loads(secret)

Retrieve credentials from Secrets Manager

credentials = get_secret()

Extract the values; if AWS_REGION isn't in the secret, use the region from the session

AWS_ACCESS_KEY_ID = credentials.get("AWS_ACCESS_KEY_ID") AWS_SECRET_ACCESS_KEY = credentials.get("AWS_SECRET_ACCESS_KEY") AWS_REGION = credentials.get("AWS_REGION", boto3.session.Session().region_name or "us-east-2")

![](/projects/static/aws-security-secretsmanager/new-9.png) * Use the up arrow to go to the top of the file * Since this piece of code uses a new package `json`, we need to import it at the top of the file. Add the following line to your import statements: ```python import json

  • Press Ctrl+O to save your changes
  • Press Ctrl+X to exit nano
  • Open config.py in Notepad:

    notepad config.py
    • Go to the end of the file and add:

      return json.loads(secret) # Retrieve credentials from Secrets Manager credentials = get_secret() # Extract the values; if AWS_REGION isn't in the secret, use the region from the session AWS_ACCESS_KEY_ID = credentials.get("AWS_ACCESS_KEY_ID") AWS_SECRET_ACCESS_KEY = credentials.get("AWS_SECRET_ACCESS_KEY") AWS_REGION = credentials.get("AWS_REGION", boto3.session.Session().region_name or "us-east-2")
  • Since this piece of code uses a new package json, we need to import it at the top of the file. Add the following line to your import statements:

import json
  • Press Ctrl+S to save the file
  • Close Notepad

๐Ÿ’ก What are these lines doing?
These lines are responsible for actually retrieving the credentials from the secret and assigning them to the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION variables that our app.py code expects:

  • secret_json = json.loads(get_secret()): This line calls the get_secret() function to retrieve the secret from Secrets Manager. The secret is returned as a JSON string, so we use json.loads() to parse it into a Python dictionary.
  • AWS_ACCESS_KEY_ID = secret_json['AWS_ACCESS_KEY_ID']: This line extracts the value of the AWS_ACCESS_KEY_ID key from the secret_json dictionary and assigns it to the AWS_ACCESS_KEY_ID variable.
  • AWS_SECRET_ACCESS_KEY = secret_json['AWS_SECRET_ACCESS_KEY']: This line does the same for the AWS_SECRET_ACCESS_KEY.
  • AWS_REGION = region_name: This line sets the AWS_REGION variable to the region_name we defined earlier.

Woohoooo! Now our application is configured to retrieve AWS credentials securely from Secrets Manager - instead of hardcoding them ๐Ÿ˜ฎโ€๐Ÿ’จ

Let's share our newly secured code with the world! ๐ŸŒŽ Remember how GitHub's secret scanning blocked our push earlier? Now that we've properly moved our credentials to AWS Secrets Manager, we can confidently push our code without exposing any sensitive information.


In this step, you're going to:


Save, Commit and Push Your Changes

๐Ÿ’ก Why is this happening?
Turns out, simply editing the config.py file is not enough for security best practices ๐Ÿคฆโ€โ™€๏ธ

The hardcoded credentials still live in your commit history, which is a record of all commits you've made to your repository. In our case, because we made an older commit in ๐Ÿด Step #2 with the hardcoded credentials, someone else could still go through the commit history to find the credentials.

To solve this, we need to rewrite the history to completely remove the commit that had the hardcoded credentials.

Remove Hardcoded Credentials from Commit History

We'll have to use use a special command called git rebase to ๐Ÿช„ rewrite history ๐Ÿช„ and remove the commit that introduced the credentials.

git rebase -i --root

๐Ÿ’ก What is git rebase -i --root?
git rebase starts a rebase session, which means rewriting your commit history.

The -i flag makes it interactive, meaning you can edit the list of commits to be rebased.

--root tells us that the rebase should start from the very first commit in your repository's history. This is useful when you need to modify commits from the beginning of your project.

๐Ÿ’ก What is drop?
Drop in the interactive rebase editor tells Git to completely remove a commit from your history as if it never existed.

This is how we'll erase the commit containing the sensitive credentials. Use this command with caution, as rewriting history can cause issues like merge conflicts (which you'll see in just a second).

๐Ÿ’ก What are merge conflicts?
Merge conflicts happen when you've changed the same lines of code in different commits.

In our case, the commit we removed had the hardcoded credentials, and the next commit we did also changed the config.py file. So Git's now confused - if you remove the commit with the hardcoded credentials, should it delete the change you made after that commit too?

If a merge conflict occurs, Git will pause the rebase and ask you to resolve the conflicts first. To resolve these conflicts, we'll need to manually edit the conflicting files to resolve these conflicts.

Resolve Merge Conflicts

  • You'll see conflict markers that look like this:
<<<<<<< HEAD # Old version with hardcoded credentials AWS_ACCESS_KEY_ID = "AKIAXXXXXXXXXXXXXXXX" AWS_SECRET_ACCESS_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" AWS_REGION = "us-east-2" ======= # New version with Secrets Manager import boto3 from botocore.exceptions import ClientError import json def get_secret(): # ... rest of the Secrets Manager code ... >>>>>>> ea89d6b (Updated config.py with Secrets Manager credentials)

๐Ÿ’ก What are these merge conflict markers?
When Git detects conflicting changes in a file, it adds special markers to show you exactly where the conflicts are:

  • <<<<<<< HEAD marks the beginning of your current version
  • ======= separates the two conflicting versions
  • >>>>>>> feature-branch marks the end of the incoming changes

To resolve the conflict, you need to choose which version to keep and remove all these markers.

  • Delete the entire section between <<<<<<< HEAD and ======= (this removes the hardcoded credentials)
  • Then, at the end of the file, delete the ======= line
  • Delete the >>>>>>> feature-branch line
  • Save the file
  • Open the file in nano:
nano config.py
  • You'll see conflict markers that look like this:
<<<<<<< HEAD # Old version with hardcoded credentials AWS_ACCESS_KEY_ID = "AKIAXXXXXXXXXXXXXXXX" AWS_SECRET_ACCESS_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" AWS_REGION = "us-east-2" ======= # New version with Secrets Manager import boto3 from botocore.exceptions import ClientError import json def get_secret(): # ... rest of the Secrets Manager code ... >>>>>>> ea89d6b (Updated config.py with Secrets Manager credentials)

๐Ÿ’ก What are these merge conflict markers?
When Git detects conflicting changes in a file, it adds special markers to show you exactly where the conflicts are:

  • <<<<<<< HEAD marks the beginning of your current version
  • ======= separates the two conflicting versions
  • >>>>>>> feature-branch marks the end of the incoming changes

To resolve the conflict, you need to choose which version to keep and remove all these markers.

  • Use the arrow keys to navigate through the file.
  • Delete the entire section between <<<<<<< HEAD and ======= (this removes the hardcoded credentials).
  • Then, at the end of the file, delete the ======= line.
  • Delete the >>>>>>> feature-branch line.
  • Press Ctrl+O to save your changes.
  • Press Enter to confirm.
  • Press Ctrl+X to exit nano.
  • Open the file in Notepad:
notepad config.py
  • You'll see conflict markers that look like this:
<<<<<<< HEAD AWS_ACCESS_KEY_ID = "AKIAXXXXXXXXXXXXXXXX" AWS_SECRET_ACCESS_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" AWS_REGION = "us-east-2" ======= # New version with Secrets Manager import boto3 from botocore.exceptions import ClientError import json def get_secret(): # ... rest of the Secrets Manager code ... >>>>>>> ea89d6b (Updated config.py with Secrets Manager credentials)

๐Ÿ’ก What are these merge conflict markers?
When Git detects conflicting changes in a file, it adds special markers to show you exactly where the conflicts are:

  • <<<<<<< HEAD marks the beginning of your current version
  • ======= separates the two conflicting versions
  • >>>>>>> feature-branch marks the end of the incoming changes

To resolve the conflict, you need to choose which version to keep and remove all these markers.

  • Delete the entire section between <<<<<<< HEAD and ======= (this removes the hardcoded credentials).
  • Then, at the end of the file, delete the ======= line.
  • Delete the >>>>>>> feature-branch line.
  • Press Ctrl+S to save the file.
  • Close Notepad.

git add config.py git commit -m "Resolved merge conflicts"

git rebase --continue

bash git push

Great job! You've just removed some prettyyyy sensitive data from your Git commit history. Now, let's verify that the AWS credentials can't be found in your public repository!


Verify Your GitHub Repository

Let's check on GitHub that the commit history is updated and your config.py file doesn't contain any sensitive information.

๐Ÿ™‹โ€โ™€๏ธ What are the other commits in the history?
The other commits are the ones made by the NextWork team when preparing this config.py for the project!

Notice how easy it is to click through the commit history and see old versions of the file. As a little Easter egg, you might even notice that one of the older versions contains AWS credentials - these are not your credentials, but credentials that were entered in the original repository before you forked it!

This just goes to show how important it is to remove sensitive data from your commit history - even if it's no longer the current version of the file, someone could still get to your secrets over the history of the repository!

Nice work! By taking the time to secure your code and remove sensitive data from your commit history, you've made development easier, not harder. Instead of worrying about accidentally exposing credentials, you can freely share and collaborate on your code!

Now that we've secured and deployed our web app, it's important to clean up the resources we created to avoid incurring unnecessary costs.


Resources to delete:

Delete the Forked GitHub repository.

Delete the Secrets Manager secret.

Delete the local repository.

Delete the resources from the Secret Mission (optional ๐Ÿ’Ž).


  • Go to your forked repository on GitHub.
  • Select Settings at the top of the repository page.
  • Scroll down to the bottom of the page to the Danger Zone section.
  • Select Delete this repository.
  • Type the repository name to confirm deletion.
  • Select Delete this repository.


๐Ÿ’ก Why delete the GitHub fork?
Even though we removed the hardcoded credentials from our code, it's good practice to delete the forked repository if you don't plan to use it further. This helps keep your GitHub account organized and removes any potential security concerns from old code versions that might still exist in the repository's commit history.

  • Go to the Secrets Manager console.

  • Select Secrets in the left navigation pane.

  • Select the secret you created for this project, named aws-access-key.

  • Click the Actions dropdown button.

  • Select Delete secret.

  • In the confirmation dialog box, type delete to confirm.

  • Click Schedule deletion.

  • Wait for the secret deletion process to complete. Secrets Manager typically waits for a recovery window (e.g., 7 days) before permanently deleting the secret. You can choose to force delete it immediately if needed.


๐Ÿ’ก Why delete Secrets Manager secret?
While Secrets Manager itself does not incur significant costs for just storing secrets, it's a good security practice to delete secrets that are no longer needed. This reduces the risk of accidental access or misuse of the secrets in the future.

  • Go back to your terminal.
  • Delete the local repository by going back to your parent folder, and then removing the repository folder from there:
cd ../ rm -rf nextwork-security-secretsmanager cd .. Remove-Item -Recurse -Force nextwork-security-secretsmanager

We created a few extra resources for this project's secret mission! Let's delete them one by one


IAM Access Key * Go to the IAM console. * Select Users in the left navigation pane. * Select your IAM user for which you created the Access Key in Step #3. * Go to the Security credentials tab. * Scroll down to the Access keys section. * Find the Access Key you created for this project (you can identify it by the description tag if you added one). * Click the Delete button next to the Access Key.

  • In the confirmation dialog box, click Delete.

๐Ÿ’ก Why delete IAM Access Key?
If you created a new IAM Access Key specifically for this project, it's a good security practice to delete it when you are finished with the project. This reduces the risk of the Access Key being compromised or misused in the future. It's recommended to only keep Access Keys that are actively being used and delete any unused ones.

  • Don't forget to also delete the .csv file you downloaded! The spreadsheet is no longer needed, and it contains a copy of your access key credentials.


S3 bucket

If you created a new S3 bucket for this project, you can delete it now:

  • Go to the S3 console.
  • Select All purpose buckets in the left navigation pane.
  • Select the bucket you created for this project.
  • Click the Delete button.
  • In the confirmation dialog box, click Delete.

Nice work! ๐Ÿ” You've successfully learned how to protect sensitive credentials using AWS Secrets Manager!

You've learned how to:

๐Ÿš€ p.s. Does it say "Still tasks to complete!" at the bottom of the screen?

This means you still have screenshots left to upload, or questions left to answer!

  1. Press Ctrl+F (Windows) or Command+F (Mac) on your keyboard.
  2. Search for the text Return to later.
  3. Jump straight to your incomplete tasks!
  4. ๐Ÿ™‹โ€โ™€๏ธ Still stuck? Ask the community!