diff --git a/app/utils/database.py b/app/utils/database.py index 285c280..d278d30 100644 --- a/app/utils/database.py +++ b/app/utils/database.py @@ -1,14 +1,24 @@ +import os +import boto3 from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker -import os +from functools import lru_cache -DATABASE_URL = ( - f"postgresql://{os.getenv('DB_USER')}:{os.getenv('DB_PASSWORD')}" - f"@{os.getenv('DB_HOST')}/{os.getenv('DB_NAME')}" -) +@lru_cache(maxsize=1) +def get_db_credentials(): + """Fetch and cache DB credentials from SSM Parameter Store""" + ssm = boto3.client('ssm') + try: + host = ssm.get_parameter(Name='/iptv-updater/DB_HOST', WithDecryption=True)['Parameter']['Value'] + user = ssm.get_parameter(Name='/iptv-updater/DB_USER', WithDecryption=True)['Parameter']['Value'] + password = ssm.get_parameter(Name='/iptv-updater/DB_PASSWORD', WithDecryption=True)['Parameter']['Value'] + dbname = ssm.get_parameter(Name='/iptv-updater/DB_NAME', WithDecryption=True)['Parameter']['Value'] + return f"postgresql://{user}:{password}@{host}/{dbname}" + except Exception as e: + raise RuntimeError(f"Failed to fetch DB credentials from SSM: {str(e)}") -engine = create_engine(DATABASE_URL) +engine = create_engine(get_db_credentials()) # Create all tables from app.models import Base diff --git a/infrastructure/stack.py b/infrastructure/stack.py index 1d2fafd..84bc320 100644 --- a/infrastructure/stack.py +++ b/infrastructure/stack.py @@ -7,6 +7,7 @@ from aws_cdk import ( aws_iam as iam, aws_cognito as cognito, aws_rds as rds, + aws_ssm as ssm, CfnOutput ) from constructs import Construct @@ -224,13 +225,32 @@ class IptvUpdaterStack(Stack): ) ) - # Update instance with userdata and DB connection info - userdata.add_commands( - f'echo "DB_HOST={db.db_instance_endpoint_address}" >> /etc/environment', - f'echo "DB_NAME=iptv_updater" >> /etc/environment', - f'echo "DB_USER={db.secret.secret_value_from_json("username").to_string()}" >> /etc/environment', - f'echo "DB_PASSWORD={db.secret.secret_value_from_json("password").to_string()}" >> /etc/environment' + # Store DB connection info in SSM Parameter Store + ssm.StringParameter(self, "DBHostParam", + parameter_name="/iptv-updater/DB_HOST", + string_value=db.db_instance_endpoint_address ) + ssm.StringParameter(self, "DBNameParam", + parameter_name="/iptv-updater/DB_NAME", + string_value="iptv_updater" + ) + ssm.StringParameter(self, "DBUserParam", + parameter_name="/iptv-updater/DB_USER", + string_value=db.secret.secret_value_from_json("username").to_string() + ) + ssm.StringParameter(self, "DBPassParam", + parameter_name="/iptv-updater/DB_PASSWORD", + string_value=db.secret.secret_value_from_json("password").to_string() + ) + + # Add SSM read permissions to instance role + role.add_managed_policy( + iam.ManagedPolicy.from_aws_managed_policy_name( + "AmazonSSMReadOnlyAccess" + ) + ) + + # Update instance with userdata instance.add_user_data(userdata.render()) # Outputs