DEV Community

Ahmed Srebrenica for AWS Community Builders

Posted on • Originally published at aws.plainenglish.io

Stop hardcoding! Use AWS Parameter Store instead (Hands-On)

Stop hardcoding! Use AWS Parameter Store instead (Hands-On)

This article is a practical guide for DevOps engineers who want to manage configuration and secrets the right way on AWS.

Figure 1: With and without Parameter Store

Introduction

If you have a database hostname, a password, and an API URL your application needs to call, where do you put them? The wrong answer is “environment variables hardcoded into your Lambda function”. The issue is: different environments (dev, prod) need different values, rotating a password means redeploying every service that uses it, and hardcoding config eventually ends up in Git (you don’t want that, trust me).

AWS has multiple services for managing configuration and secrets, but today we will focus on AWS Systems Manager Parameter Store.

AWS Parameter Store gives you a central, secure, hierarchical place to store configuration and secrets, and any AWS service can read from it at runtime without you changing a line of application code. Think of it as a managed configuration database where you store both, plain config values and encrypted secrets, organized in a folder-like structure.

In this article, we will create a set of parameters in Parameter Store and build a Lambda function that uses them. Changing a parameter value will change what the Lambda does, with no redeployment needed.

Prerequisites

  1. Create an AWS Account.

  2. Console access with permissions for: System Manager, Lambda, and IAM.

    **NOTE: **Everything in this guide is free or within free tier limits.

What is AWS System Manager Parameter Store?

Per AWS, Parameter Store is a tool in AWS Systems Manager that provides secure, hierarchical storage for configuration data management and secrets management. You can store data such as passwords, database strings, Amazon Machine Image (AMI) IDs, and license codes as parameter values. You can store values as plain text or encrypted data. You can reference Systems Manager parameters in your scripts, commands, SSM documents, and configuration and automation workflows by using the unique name that you specified when you created the parameter.

Parameter Types

Parameter Store supports three types of values:

  1. String — plain text. Use this for non-sensitive config like hostnames, URLs, or feature flag values.

  2. StringList — a comma-separated list of strings. Useful for storing a list of IPs, ARNs, or environment names in a single parameter.

  3. SecureString — the value is encrypted at rest using AWS KMS. Use this for passwords, tokens, and any sensitive data.

Parameter Tiers

Parameter Store has different size limits for parameter values depending on the parameter tier you use. Standard parameters: Maximum value size of 4 KB, and Advanced parameters: Maximum value size of 8 KB.

Hierarchy

Parameters are organized using forward-slash paths — similar to a file system:

/myapp/dev/db_host
/myapp/dev/api_url
/myapp/prod/db_host
/myapp/prod/api_url
Enter fullscreen mode Exit fullscreen mode

This makes it easy to retrieve all configuration for a specific environment at once, and it simplifies IAM policies — you can grant access to **/myapp/prod/ **without listing every individual parameter.

Key Characteristics

  • Free on the Standard tier — no per-parameter cost

  • Encrypted secrets using AWS KMS (SecureString type)

  • Full version history — every update creates a new version

  • Tight integration with Lambda, ECS, CloudFormation, and CodePipeline

  • Write operations (create, update, delete) are logged in AWS CloudTrail by default. Read operations require enabling data event logging in CloudTrail separately.

Parameter Store vs AWS Secrets Manager

AWS has more than one service that can store configuration and secrets. Before jumping into the hands-on, it is worth understanding where Parameter Store fits and when you should reach for something else.

**Secrets Manager** is the other AWS service most commonly compared to Parameter Store. Both can store secrets, but they are designed for different needs.

Figure 2: Parameter Store vs Secrets Manager, custom table

Use Parameter Store for configuration and static secrets. Use Secrets Manager when you need automatic credential rotation — database passwords, API keys that expire, and OAuth tokens.

Parameter Store vs AWS AppConfig

AppConfig is a separate service built on top of Parameter Store, designed specifically for feature flags and application configuration with deployment controls.

AppConfig is a separate service built on top of Parameter Store, designed specifically for feature flags and application configuration with deployment controls.

Choose AppConfig when you need:

  • Gradual rollouts (deploy config to 10% of instances first, then 100%)

  • Automatic rollback if a bad config causes errors

  • Configuration validation before deployment

Choose Parameter Store when you need:

  • Simple key-value config without deployment strategy complexity

  • Secrets (AppConfig is not designed for sensitive values)

  • Free storage with no additional overhead

Creating the Parameters

We will create three parameters that our Lambda function will use. They cover the most common types you will encounter in real projects.

Parameter I — Database hostname (string)

A plain-text configuration value. Nothing sensitive, so no encryption needed.

  1. Go to **Parameter Store **in the console

  2. Click Create parameter

  3. Fill in:

Name: /myapp/dev/db_host

Description: Database hostname for myapp dev environment

Tier: Standard

Type: String

Value: dev-db.ahmed.com

Data type: text

  1. Add tags: Environment = dev, App = myapp

  2. Click Create parameter

Figure 3: Create db_host String type

Parameter II — API URL (String)

This is the parameter the Lambda function will actively read and act on. The function will call whatever URL is stored there. Change the URL, the Lambda will call a different endpoint on the next run — no code change needed.

  1. Go to **Parameter Store **in the console

  2. Click Create Parameter

  3. Fill in

Name: /myapp/dev/api_url

Description: API endpoint the application calls

Tier: Standard

Type: String

Value: https://jsonplaceholder.typicode.com/posts/1

Data type: text

  1. Add tags: Environment = dev, App = myapp

  2. Click Create parameter

    NOTE: JSONPlaceholder is free public REST API for testing — no account or API key needed.

Figure 4: Create api_url String type

What have we created?

We created three parameters, and they are all for dev. Search for **/myapp/dev/ **in the Parameter Store list. All three parameters appear together, filtered by their path prefix.

In a real application, this means one API call loads all configuration for an environment — your app asks for */myapp/dev/ **and gets back every key under that path at once. For example, if we promote to production, it reads */myapp/prod/ **instead. Same code, different parameters

Figure 5: Created parameters

Using the Parameters — Lambda function

Now we put the parameters to work. The Lambda function will:

  1. Read /myapp/dev/db_host and /myapp/dev/api_url from Parameter Store in a single call

    1. Make a real HTTP request to the API URL
    2. Return the database host and the API response together

Step I — Create the Lambda function

  1. Go to **AWS Console >Lambda >Create function**

  2. Select Author from scratch

  3. Fill in:

**Function name: **parameter-store-demo

Runtime: Python 3.14

  1. Leave permissions as default and click Create function

Figure 6: Create Lambda function

Step II — Grant Permission to read from Parameter store

By default the Lambda execution role only has CloudWatch Logs access. We need to add SSM read permission.

  1. Click the Configuration tab > Permissions > Edit

Figure 7: Configuration tab > Permissions > Edit

  1. Click View role details in IAM

Figure 8: View role details in IAM

  1. Click Add permissions > Attach policies

  2. Search for AmazonSSMReadOnlyAccess and attach it

Figure 9: Attach AmazonSSMReadOnlyAccess

Step III — Write the code

  1. Click the Code tab in Lambda

    1. Replace the entire contents of lambda_function.py with:

    import boto3
    import urllib.request
    import json

    def lambda_handler(event, context):
    ssm = boto3.client('ssm')

    # Load two parameters in a single API call
    result = ssm.get_parameters(
        Names=['/myapp/dev/db_host', '/myapp/dev/api_url']
    )
    
    # Build a simple config dict from the results
    config = {p['Name'].split('/')[-1]: p['Value'] for p in result['Parameters']}
    
    # Make a real HTTP request to the URL from Parameter Store
    with urllib.request.urlopen(config['api_url']) as response:
        api_data = json.loads(response.read())
    
    return {
        'db_host': config['db_host'],
        'url_called': config['api_url'],
        'api_response': api_data
    }
    

    NOTE: get_parameters (plural) fetches multiple parameters in one API call — more efficient than calling get_parameter once per value.
    The code has no hardcoded URLs or hostnames. It asks Parameter Store, then acts on whatever it gets back.
    Important: Lambda and the parameters must be in the same AWS region. A region mismatch produces a ParameterNotFound error even if the parameter name is correct.

Step IV — Test

  1. Click Deploy to deploy the code

  2. Click Test to create the test

Figure 10: Click Deploy and then Test

  1. Create new test event and name it test

Figure 11: Create new test event

  1. Save it and click the Invoke

Figure 12: Creating the test event

  1. The Lambda loaded both parameters and returned a real API response. No hardcoded values anywhere in the code. Which means, everything is working correctly.

Figure 13: Lambda function output

Update the API URL

This is where Parameter Store shows its value. We will update both parameters — the Lambda behavior changes instantly, with no redeployment.

Update the API URL:

  1. Go to Parameter Store > /myapp/dev/api_url

  2. Click Edit >change the value to https://jsonplaceholder.typicode.com/posts/5

  3. Click Save changes

Update the database host (simulating a failover to a new database server):

  1. Open /myapp/dev/db_host

  2. Click Edit >change the value to dev-db.ahmed.srebrenica.com

  3. Click Save changes

Now open either parameter and click the History tab and you will see Version 1 and Version 2 with timestamps. Parameter Store keeps a full history of every change automatically.

Figure 14: api_url — history tab

Figure 15: db_host — history tab

Back in Lambda, click Test again:

Figure 16: Output after update

Both values updated! The Lambda code is identical to what we deployed. This is the core value of Parameter Store — application’s behavior is controlled by configuration, not by code.

Best practices

The hands-on above uses shortcuts that are fine for a demo, but shouldn’t go into production. Here is what to do differently in a real environment.

  1. Never use broad managed policies on your roles

In this hands-on, we attached AmazonSSMReadOnlyAccess to the Lambda role for convenience. In production, this is too permissive; it grants read access to every parameter in your account, including parameters that belong to other applications or contain sensitive data. Instead, create a custom inline policy scoped to only the path your function needs.

2. Always encrypt sensitive values with SecureString

Any parameter that contains a password, token, API key, or any value you would not want to expose in logs should be stored as SecureString, not String. SecureString encrypts the value at rest using AWS KMS.

For production, go one step further: use a **customer-managed KMS key (CMK) instead of the default **alias/aws/ssm. A CMK gives you full control; you can rotate the key, restrict which roles can use it, and audit every decrypt operation.

3. Never log parameter values

The application will read SecureString parameters and decrypt them. Make sure those values never appear in CloudWatch Logs. A single **print(password) **or an unhandled exception that dumps local variables can expose your secrets in plain text in your log stream.

4. Design your naming hierarchy before you start

It is much harder to rename parameters after services depend on them. Agree on a convention before you create the first parameter:

/team/environment/service/key
/platform/prod/payments/db_host
/platform/prod/payments/api_url
Enter fullscreen mode Exit fullscreen mode

A consistent hierarchy makes IAM policies easier, bulk reads cleaner, and environment promotion predictable.

5. Tag Every Parameter

Tags make it easy to understand who owns a parameter, filter by environment, and set up cost allocation:

  • Environment = prod

  • App = payments

  • Team = backend

  • ManagedBy = terraform (if using IaC)

Conclusion

In this article, we went from zero to a working Parameter Store setup entirely from the AWS Console.

We created two parameters, a database hostname and an API URL — organized under a **/myapp/dev/ **hierarchy. We then built a Lambda function that reads both parameters at runtime and makes a real HTTP request to the URL stored in Parameter Store. Finally, we updated both parameters and ran Lambda again without touching a single line of code, the behavior changed instantly.

That last step is the whole point. Application stops caring about specific values. It asks Parameter Store, and you control the answer from one central place.

A few things to take with you:

  • The hierarchy (/app/env/key) is not optional — design it from day one, it makes environment promotion and IAM policies much easier.

  • SecureString exists for anything sensitive — passwords, tokens, API keys — encrypted at rest with KMS.

  • The Standard tier is free — there is no reason not to start using this today.

  • All parameter changes are logged in CloudTrail — every update is auditable.

If you like this story, please clap and follow me.
Check out my website for basic information about me: ahmedsrebrenica.com.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.