DEV Community

Syed Mohammad Ibrahim
Syed Mohammad Ibrahim

Posted on

2

Credentials substitution at runtime in Python

Introduction

Often we hear that credentials should not be hardcoded in the code or Version Control (like git). You can leverage the dynamic substitution of such credentials using Environment variables tied to the code as a variable.

Pre-requisite

  • Python 3.8 or up
  • PyYaml - To read YAML configuration file

Steps

  • Create a yaml file as the following
# credentials.yml

aws:
  access_key_id: "${AWS_ACCESS_KEY_ID}"
  secret_access_key: "${AWS_SECRET_ACCESS_KEY}"
Enter fullscreen mode Exit fullscreen mode
  • We will read this yaml file and get the python dictionary object
# main.py
from typing import Dict
import yaml

def read_credentials_file() -> Dict:
  try:
    with open("credentials.yml", mode="r", encoding="utf-8") as cred_file:
      return yaml.safe_load(cred_file)
  except yaml.YAMLError as yaml_err:
    print(f"Unable to read the file. Error: {yaml_err}")
    raise

Enter fullscreen mode Exit fullscreen mode
  • We will use the string.Template from the standard library to substitute the value from the environment variables
# main.py
import string
import os

def substitute_creds(creds: Dict) -> None:
  creds["aws"]["access_key_id"] = string.Template(
    creds["aws"]["access_key_id"]
  ).substitute(
    {"AWS_ACCESS_KEY_ID": os.getenv("AWS_ACCESS_KEY_ID")}
  )

  creds["aws"]["secret_access_key"] = string.Template(
    creds["aws"]["secret_access_key"]
  ).substitute(
    {"AWS_SECRET_ACCESS_KEY": os.getenv("AWS_SECRET_ACCESS_KEY")}
  )
Enter fullscreen mode Exit fullscreen mode
  • Add the following two variables as part of the environment. They can be added in the .env file as well
$ export AWS_ACCESS_KEY_ID="abcd1234"
$ export AWS_SECRET_ACCESS_KEY="secret123"
Enter fullscreen mode Exit fullscreen mode

Complete Program

# main.py
from typing import Dict
import string
import yaml
import os

def read_credentials_file() -> Dict:
  try:
    with open("credentials.yml", mode="r", encoding="utf-8") as cred_file:
      return yaml.safe_load(cred_file)
  except yaml.YAMLError as yaml_err:
    print(f"Unable to read the file. Error: {yaml_err}")
    raise

def substitute_creds(creds: Dict) -> None:
  creds["aws"]["access_key_id"] = string.Template(
    creds["aws"]["access_key_id"]
  ).substitute(
    {"AWS_ACCESS_KEY_ID": os.getenv("AWS_ACCESS_KEY_ID")}
  )

  creds["aws"]["secret_access_key"] = string.Template(
    creds["aws"]["secret_access_key"]
  ).substitute(
    {"AWS_SECRET_ACCESS_KEY": os.getenv("AWS_SECRET_ACCESS_KEY")}
  )

if __name__ == "__main__":
  credentials = read_credentials_file()
  substitute_creds(credentials)

  # WARNING: Never print or log credentials or any sensitive information
  print(f"Credentials: {credentials}")
Enter fullscreen mode Exit fullscreen mode
  • The above code when run should produce the following output
$ python3 main.py
Credentials: {"aws": {"access_key_id": "abcd1234", "secret_access_key": "secret123"}}
Enter fullscreen mode Exit fullscreen mode

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay