Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dbtp 1298 postgres docker tests #287

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions postgres/lambda.tf
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ data "aws_security_group" "rds-endpoint" {
# tflint-ignore: terraform_unused_declarations
data "archive_file" "lambda" {
type = "zip"
source_file = "${path.module}/manage_users.py"
output_path = "${path.module}/manage_users.zip"
source_file = "${path.module}/manage-users/manage_users/manage_users.py"
output_path = "${path.module}/manage-users/manage_users/manage_users.zip"
depends_on = [
aws_iam_role.lambda-execution-role
]
Expand Down
17 changes: 17 additions & 0 deletions postgres/manage-users/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM python:3.9
RUN apt-get update && apt-get install -y curl
RUN curl -sSL https://install.python-poetry.org | python3 -
ENV PATH="/root/.local/bin:$PATH"

WORKDIR /src
COPY poetry.lock ./
COPY pyproject.toml ./

RUN poetry update
COPY . ./
RUN poetry install --no-root

HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1

CMD ["poetry", "run", "pytest"]
8 changes: 8 additions & 0 deletions postgres/manage-users/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
build:
docker-compose build

test: down build
docker-compose run manage-users poetry run pytest

down:
docker-compose down
7 changes: 7 additions & 0 deletions postgres/manage-users/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# manage-users

## Setup

```shell
brew install docker-compose
```
31 changes: 31 additions & 0 deletions postgres/manage-users/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
services:

Check warning on line 1 in postgres/manage-users/docker-compose.yml

View workflow job for this annotation

GitHub Actions / trufflehog

Found unverified Postgres result 🐷🔑
manage-users:
networks:
- testnet
build:
context: ../manage-users
depends_on:
- postgres-unittest
ports:
- '9004:8080'
environment:
DATABASE_URL: postgres://test_user:test_pw@postgres-unittest:5432/test_db
volumes:
- ./:/src

postgres-unittest:
networks:
- testnet
image: postgres:13
restart: always
command: 'postgres -c log_statement=all -c fsync=off -c vm.zone_reclaim_mode=0 -c synchronous_commit=off -c checkpoint_completion_target=0.9 -c random_page_cost=1.1'
ports:
- "5432:5432"
environment:
- POSTGRES_DB=test_db
- POSTGRES_USER=test_user
- POSTGRES_PASSWORD=test_pw

networks:
testnet:
driver: bridge
Empty file.
108 changes: 108 additions & 0 deletions postgres/manage-users/manage_users/manage_users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import json
import boto3
import psycopg2
from botocore.exceptions import ClientError


def create_or_update_db_user(conn, cursor, username, password, permissions):
cursor.execute(f"SELECT * FROM pg_catalog.pg_user WHERE usename = '{username}'")

if cursor.fetchone() is not None:
update_db_user_password(conn, cursor, username, password)
else:
create_db_user(conn, cursor, username, password, permissions)


def update_db_user_password(conn, cursor, username, password):
cursor.execute(f"ALTER USER {username} WITH ENCRYPTED PASSWORD '%s'" % password)
conn.commit()


def create_db_user(conn, cursor, username, password, permissions):
cursor.execute(f"CREATE USER {username} WITH ENCRYPTED PASSWORD '%s'" % password)
cursor.execute(f"GRANT {username} to postgres;")
cursor.execute(f"GRANT {', '.join(permissions)} ON ALL TABLES IN SCHEMA public TO {username};")
cursor.execute(f"ALTER DEFAULT PRIVILEGES FOR USER application_user IN SCHEMA public GRANT {', '.join(permissions)} ON TABLES TO {username};")

if 'INSERT' in permissions:
cursor.execute(f"GRANT CREATE ON SCHEMA public TO {username};")

conn.commit()


def create_or_update_user_secret(ssm, user_secret_name, user_secret_string, event):
user_secret_description = event['SecretDescription']
copilot_application = event['CopilotApplication']
copilot_environment = event['CopilotEnvironment']

user_secret = None

try:
user_secret = ssm.put_parameter(
Name=user_secret_name,
Description=user_secret_description,
Value=json.dumps(user_secret_string),
Tags=[
{'Key': 'managed-by', 'Value': 'Terraform'},
{'Key': 'copilot-application', 'Value': copilot_application},
{'Key': 'copilot-environment', 'Value': copilot_environment},
],
Type="SecureString",
)
except ClientError as error:
if error.response["Error"]["Code"] == "ParameterAlreadyExists":
user_secret = ssm.put_parameter(
Name=user_secret_name,
Description=user_secret_description,
Value=json.dumps(user_secret_string),
Overwrite=True,
)

return user_secret


def handler(event, context):
print("REQUEST RECEIVED:\n" + json.dumps(event))

db_master_user_secret_arn = event['MasterUserSecretArn']
user_secret_name = event['SecretName']
username = event['Username']
user_permissions = event['Permissions']

secrets_manager = boto3.client("secretsmanager")
ssm = boto3.client("ssm")

master_user = json.loads(secrets_manager.get_secret_value(SecretId=db_master_user_secret_arn)["SecretString"])

user_password = secrets_manager.get_random_password(
PasswordLength=16,
ExcludeCharacters='[]{}()"@/\\;=?&`><:|#',
ExcludePunctuation=True,
IncludeSpace=False,
)["RandomPassword"]

user_secret_string = {
"username": username,
"password": user_password,
"engine": event["DbEngine"],
"port": event["DbPort"],
"dbname": event["DbName"],
"host": event["DbHost"],
"dbInstanceIdentifier": event["dbInstanceIdentifier"]
}

conn = psycopg2.connect(
dbname=event["DbName"],
user=master_user["username"],
password=master_user["password"],
host=event["DbHost"],
port=event["DbPort"]
)

cursor = conn.cursor()

create_or_update_db_user(conn, cursor, username, user_password, user_permissions)
create_or_update_user_secret(ssm, user_secret_name, user_secret_string, event)

cursor.close()
conn.close()
Loading
Loading