DEV Community

Roger Chi
Roger Chi

Posted on

AWS AppConfig multi-accounts, multi-environments with ease

AppConfig is AWS's native solution for feature flagging and dynamic configuration management. It provides a comparable feature set to third party feature flagging tools such as LaunchDarkly or StatSig. Coming from an organization that used these third party tools, there were some hurdles that I encountered when implementing AppConfig for our applications with the same ease as these third party tools. In this article, I will describe these challenges and our solutions to them. Specifically, I will cover these topics:

  • AWS Organizations setup with an AppConfig shared service account
  • Configuring IAM roles and Systems Manager Parameters to simplify application access to the correct environments configured in AppConfig
  • Setting up AppConfig Agent with Lambda functions, including Docker Image Functions

Authorization and access compared to third party tools

If you're familiar with using a feature flagging tool such as LaunchDarkly, you will be used to using API keys that are associated with specific environments. This abstracts the association between an environment (a set of flags/configs tied to a deployment environment, such as dev, staging, or prod) and the application. The application client just needs to be configured with the correct API key, and will pull flags that are specific to that environment without needing to be explicitly configured with information about that environment.

With AppConfig, there is no concept of API keys. All access to the service is through the AWS native IAM integration. So the question is how best to set up AppConfig and the IAM roles allowed to access it in a multi-account, multi-environment AWS Organization?

AWS Organization setup

AppConfig AWS Organization structure

The structure we settled on is:

  • A separate, shared services AWS account dedicated to AppConfig
  • IAM roles specific to an AppConfig "Application"
  • For each Application and Environment within that application, an IAM role that grants access to get configurations specific to that environment
  • SSM Systems manager parameters for each Application deployed to each workload account that specifies the role to assume and the environment name
  • AWS IAM Identity Center permission set granting access to the AppConfig account

CloudFormation templates

To implement this structure, we'll need two CloudFormation templates:

  1. A template for the AppConfig account that creates the application, environments, and cross-account IAM roles
  2. A template for the workload accounts (dev/prod) that creates the SSM parameters

AppConfig Account Template

Deploy this template to your central AppConfig account. It creates an AppConfig application with dev and prod environments, plus the IAM roles that will be assumed by applications in the dev and prod OUs. The AssumeRolePolicyDocument can be modified to support your specific AWS Organization structure (for example, granting access to a specific account, etc.).

The IAM roles created in the AppConfig account need policies that grant access to the appropriate AppConfig resources. The policy below shows the permissions needed:

  1. Basic AppConfig read operations like GetConfiguration and StartConfigurationSession scoped to the specific environment
  2. Additional list/describe operations needed by the AppConfig Agent to discover configurations and lookup ids based on names.
# Deploy this template to the AppConfig account
Parameters:
  ApplicationName:
    Type: String
    Description: Name of the AppConfig application
    Default: myapp

  prodOuId:
    Type: String
    Description: ID of the Production OU

  sdlcOuId:
    Type: String
    Description: ID of the SDLC OU

  sandboxOuId:
    Type: String
    Description: ID of the Sandbox OU

  organizationPrincipalId:
    Type: String
    Description: ID of the Organization Principal

  organizationRootOuId:
    Type: String
    Description: ID of the Organization Root OU

Resources:
  Application:
    Type: AWS::AppConfig::Application
    Properties:
      Name: !Ref ApplicationName
      Description: 'Feature flags and configuration for applications'

  ProdEnvironment:
    Type: AWS::AppConfig::Environment
    Properties:
      ApplicationId: !Ref Application
      Name: prod
      Description: 'Production environment'

  DevEnvironment:
    Type: AWS::AppConfig::Environment
    Properties:
      ApplicationId: !Ref Application
      Name: dev
      Description: 'Development environment'

  ProdAccessRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub 'appconfig-${ApplicationName}-prod'
      Description: !Sub 'Cross-account access role for ${ApplicationName} Production AppConfig environment'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              AWS: '*'
            Condition:
              'ForAnyValue:StringLike':
                'aws:PrincipalOrgPaths': !Sub '${organizationPrincipalId}/${organizationRootOuId}/${prodOuId}/*'
      Policies:
        - PolicyName: AppConfigAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - appconfig:GetConfiguration
                  - appconfig:StartConfigurationSession
                  - appconfig:GetLatestConfiguration
                Resource: !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}/environment/${ProdEnvironment}/configuration/*'
              - Effect: Allow
                Action:
                  - appconfig:GetApplication
                  - appconfig:GetEnvironment
                  - appconfig:GetConfigurationProfile
                  - appconfig:ListApplications
                  - appconfig:ListConfigurationProfiles
                  - appconfig:ListEnvironments
                  - appconfig:ListHostedConfigurationVersions
                Resource: 
                  - !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}'
                  - !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}/environment/*'
                  - !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}/configurationprofile/*'

  DevAccessRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub 'appconfig-${ApplicationName}-dev'
      Description: !Sub 'Cross-account access role for ${ApplicationName} Development AppConfig environment'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              AWS: '*'
            Condition:
              'ForAnyValue:StringLike':
                'aws:PrincipalOrgPaths': 
                  - !Sub '${organizationPrincipalId}/${organizationRootOuId}/${sdlcOuId}/*'
                  - !Sub '${organizationPrincipalId}/${organizationRootOuId}/${sandboxOuId}/*'
      Policies:
        - PolicyName: AppConfigAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - appconfig:GetConfiguration
                  - appconfig:StartConfigurationSession
                  - appconfig:GetLatestConfiguration
                Resource: !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}/environment/${DevEnvironment}/configuration/*'
              - Effect: Allow
                Action:
                  - appconfig:GetApplication
                  - appconfig:GetEnvironment
                  - appconfig:GetConfigurationProfile
                  - appconfig:ListApplications
                  - appconfig:ListConfigurationProfiles
                  - appconfig:ListEnvironments
                  - appconfig:ListHostedConfigurationVersions
                Resource: 
                  - !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}'
                  - !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}/environment/*'
                  - !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}/configurationprofile/*'

Outputs:
  ApplicationId:
    Description: AppConfig Application ID
    Value: !Ref Application

  ProdEnvironmentId:
    Description: Production Environment ID
    Value: !Ref ProdEnvironment

  DevEnvironmentId:
    Description: Development Environment ID
    Value: !Ref DevEnvironment
Enter fullscreen mode Exit fullscreen mode

Workload Account Template

Deploy this template to each of your workload accounts (development and production). It creates SSM parameters that applications will use to discover the correct IAM role to assume and environment ID to use.

# Deploy this template to each workload account (dev/prod)
Parameters:
  ApplicationName:
    Type: String
    Description: Name of the AppConfig application
    Default: myapp

  AppConfigAccountId:
    Type: String
    Description: AWS Account ID where AppConfig is deployed

  Environment:
    Type: String
    Description: Environment name (dev or prod)
    AllowedValues: [dev, prod]

Resources:
  AppConfigRoleArnParameter:
    Type: AWS::SSM::Parameter
    Properties:
      Name: !Sub '/appconfig/${ApplicationName}/role-arn'
      Type: String
      Value: !Sub 'arn:aws:iam::${AppConfigAccountId}:role/appconfig-${ApplicationName}-${Environment}'
      Description: !Sub 'Cross-account role ARN for ${ApplicationName} AppConfig access'

  AppConfigEnvironmentNameParameter:
    Type: AWS::SSM::Parameter
    Properties:
      Name: !Sub '/appconfig/${ApplicationName}/environment-name'
      Type: String
      Value: !Ref Environment
      Description: !Sub 'AppConfig Environment Name for ${ApplicationName} ${Environment} environment'
Enter fullscreen mode Exit fullscreen mode

When deploying these templates:

  1. First deploy the AppConfig account template
  2. Then deploy the workload account template to each account, using:
    • The appropriate Environment value (dev/prod)
    • The AppConfigAccountId where you deployed the first template

This setup provides a consistent way for applications to discover and access their AppConfig configuration, regardless of which account or environment they're running in. In the next section, we'll look at how applications can use these SSM parameters to access their configuration.

Setting up AppConfig Agent for Lambda functions

CDK code

const APP_NAME = 'myapp';

export function enableAppConfig(fn: LambdaFunction) {
  const appConfigRoleArn = StringParameter.fromStringParameterName(
    fn,
    'AppConfigRoleArn',
    `/appconfig/${APP_NAME}/role-arn`,
  ).stringValue;
  const appConfigEnvironment = StringParameter.fromStringParameterName(
    fn,
    'AppConfigEnvironment',
    `/appconfig/${APP_NAME}/environment-name`,
  ).stringValue;
  const appConfigRole = Role.fromRoleArn(fn, 'AppConfigRole', appConfigRoleArn);
  fn.addEnvironment('AWS_APPCONFIG_EXTENSION_ROLE_ARN', appConfigRoleArn);
  fn.addEnvironment('APPCONFIG_ENVIRONMENT', appConfigEnvironment);
  if (!fn.role) {
    throw new Error('Lambda role is undefined');
  }
  appConfigRole.grantAssumeRole(fn.role);
}

export function enableAppConfigLayer(fn: LambdaFunction) {
  let appConfigLayer: ILayerVersion;
  if (fn.architecture === Architecture.ARM_64) {
    appConfigLayer = LayerVersion.fromLayerVersionArn(
      fn,
      'AppConfigLayer',
      'arn:aws:lambda:us-west-2:359756378197:layer:AWS-AppConfig-Extension-Arm64:131',
    );
  } else {
    appConfigLayer = LayerVersion.fromLayerVersionArn(
      fn,
      'AppConfigLayer',
      'arn:aws:lambda:us-west-2:359756378197:layer:AWS-AppConfig-Extension:229',
    );
  }
  fn.addLayers(appConfigLayer);
}

export class DockerImageFunction extends CdkDockerImageFunction {
  constructor(scope: Construct, id: string, props: DockerImageFunctionProps) {
    super(scope, id, props);
    enableAppConfig(this);
  }
}

export class NodejsFunction extends CdkNodejsFunction {
  constructor(scope: Construct, id: string, props: NodejsFunctionProps) {
    super(scope, id, props);
    enableAppConfig(this);
    enableAppConfigLayer(this);
  }
}

export class PythonFunction extends CdkPythonFunction {
  constructor(scope: Construct, id: string, props: PythonFunctionProps) {
    super(scope, id, props);
    enableAppConfig(this);
    enableAppConfigLayer(this);
  }
}
Enter fullscreen mode Exit fullscreen mode

Docker Image Functions

Docker image functions can't use the AppConfig Agent Lambda Layer, so we need to build our own. This Dockerfile builds a base image with the AppConfig extension, and then builds the application on top of that. The extension is downloaded from the AWS public registry, and then installed into the /opt/extensions directory. The application is then built on top of that base image. The access tokens are only used in the first stage, so they are not included in the final image.

# First stage to fetch AppConfig extension
FROM amazon/aws-cli:latest as appconfig-extension

ARG INCLUDE_APPCONFIG=0
ARG AWS_DEFAULT_REGION
ARG AWS_ACCESS_KEY_ID
ARG AWS_SECRET_ACCESS_KEY
ARG AWS_SESSION_TOKEN

ENV AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
ENV AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
ENV AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
ENV AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN}

# Install unzip before trying to use it
RUN yum install -y unzip

# Create directory and download extension if enabled
RUN mkdir -p /opt/extensions && \
    if [ "$INCLUDE_APPCONFIG" = "1" ]; then \
        aws lambda get-layer-version-by-arn \
        --arn arn:aws:lambda:us-west-2:359756378197:layer:AWS-AppConfig-Extension:229 \
        --query 'Content.Location' --output text | xargs curl -o layer.zip && \
        unzip -j layer.zip "extensions/*" -d /opt/extensions && \
        rm layer.zip; \
    fi

# Main build stage
FROM python:3.13-slim as base

# Copy the AppConfig extension from the first stage
RUN mkdir -p /opt/extensions
COPY --from=appconfig-extension /opt/extensions /opt/extensions
RUN ls -la /opt/extensions
Enter fullscreen mode Exit fullscreen mode

Conclusion

This architecture provides several key benefits for managing feature flags and configuration across a multi-account AWS organization:

  1. Centralized Management: By hosting AppConfig in a dedicated account, we create a single source of truth for all feature flags and configuration. This makes it easier to manage and audit configuration changes across environments.

  2. Secure Access Control: Using AWS Organizations and OU-based IAM roles ensures that:

    • Production applications can only access production configurations
    • Development applications can only access development configurations
    • Access is automatically granted to new accounts added to the appropriate OUs
  3. Simple Application Integration:

    • Applications only need to know their application name to discover the appropriate role and environment
    • The same application code works across all environments without environment-specific configuration
    • SSM Parameters provide a consistent interface for applications to discover their AppConfig settings
  4. Lambda Integration: The provided CDK constructs make it easy to add AppConfig support to Lambda functions:

    • Automatic layer addition for Node.js and Python functions
    • Docker image support with a base image that includes the AppConfig extension
    • Environment-aware configuration without code changes

This solution achieves the same simplicity of third-party feature flag services while maintaining the benefits of AWS's native services and security model. Teams can deploy applications across accounts and environments without worrying about AppConfig access configuration, while security teams can maintain strict access controls through AWS Organizations.

Bonus, for users of org-formation-cli

Tasks file:

Parameters:
  <<: !Include '../../_parameters.yml'

  appName:
    Type: String
    Default: 'myapp'

AppConfigMyApp:
  Type: update-stacks
  Template: ./application.yml
  StackName: !Sub '${resourcePrefix}-appconfig-${appName}'
  StackDescription: !Sub 'AppConfig Application, Environments, Roles and Parameters for ${appName}'
  TerminationProtection: false
  DefaultOrganizationBindingRegion: 'us-west-2'
  OrganizationBindings:
    ApplicationBinding:
      Account: !Ref AppConfigAccount
    ProdParametersBinding:
      IncludeMasterAccount: false
      OrganizationalUnit:
        - !Ref ProdOu
      Region: 'us-west-2'
    DevParametersBinding:
      IncludeMasterAccount: false
      OrganizationalUnit:
        - !Ref SdlcOu
        - !Ref SandboxOu
      Region: 'us-west-2'
  Parameters:
    applicationName: !Ref appName
    prodOuId: !Ref ProdOu
    sdlcOuId: !Ref SdlcOu
    sandboxOuId: !Ref SandboxOu
    organizationPrincipalId: !Ref organizationPrincipalId
    organizationRootOuId: !Ref organizationRootOuId
    appConfigAccountId: !Ref AppConfigAccount 
Enter fullscreen mode Exit fullscreen mode

application.yml:

Parameters:
  applicationName:
    Type: String
    Description: Name of the AppConfig application

  prodOuId:
    Type: String
    Description: ID of the Production OU

  sdlcOuId:
    Type: String
    Description: ID of the SDLC OU

  sandboxOuId:
    Type: String
    Description: ID of the Sandbox OU

  organizationPrincipalId:
    Type: String
    Description: ID of the Organization Principal

  organizationRootOuId:
    Type: String
    Description: ID of the Organization Root OU

  appConfigAccountId:
    Type: String
    Description: ID of the AppConfig account

Resources:
  # AppConfig Resources - Created in AppConfig Account
  Application:
    Type: AWS::AppConfig::Application
    OrganizationBinding: !Ref ApplicationBinding
    Properties:
      Name: !Ref applicationName
      Description: 'Feature flags and configuration for applications'

  ProdEnvironment:
    Type: AWS::AppConfig::Environment
    OrganizationBinding: !Ref ApplicationBinding
    Properties:
      ApplicationId: !Ref Application
      Name: prod
      Description: 'Production environment'

  DevEnvironment:
    Type: AWS::AppConfig::Environment
    OrganizationBinding: !Ref ApplicationBinding
    Properties:
      ApplicationId: !Ref Application
      Name: dev
      Description: 'Development environment'

  ProdAccessRole:
    Type: AWS::IAM::Role
    OrganizationBinding: !Ref ApplicationBinding
    Properties:
      RoleName: !Sub 'appconfig-${applicationName}-prod'
      Description: !Sub 'Cross-account access role for ${applicationName} Production AppConfig environment'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              AWS: '*'
            Condition:
              'ForAnyValue:StringLike':
                'aws:PrincipalOrgPaths': !Sub '${organizationPrincipalId}/${organizationRootOuId}/${prodOuId}/*'
      Policies:
        - PolicyName: AppConfigAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - appconfig:GetConfiguration
                  - appconfig:StartConfigurationSession
                  - appconfig:GetLatestConfiguration
                Resource: !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}/environment/${ProdEnvironment}/configuration/*'
              - Effect: Allow
                Action:
                  - appconfig:GetApplication
                  - appconfig:GetEnvironment
                  - appconfig:GetConfigurationProfile
                  - appconfig:ListApplications
                  - appconfig:ListConfigurationProfiles
                  - appconfig:ListEnvironments
                  - appconfig:ListHostedConfigurationVersions
                Resource: 
                  - !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}'
                  - !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}/environment/*'
                  - !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}/configurationprofile/*'

  DevAccessRole:
    Type: AWS::IAM::Role
    OrganizationBinding: !Ref ApplicationBinding
    Properties:
      RoleName: !Sub 'appconfig-${applicationName}-dev'
      Description: !Sub 'Cross-account access role for ${applicationName} Development AppConfig environment'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              AWS: '*'
            Condition:
              'ForAnyValue:StringLike':
                'aws:PrincipalOrgPaths': 
                  - !Sub '${organizationPrincipalId}/${organizationRootOuId}/${sdlcOuId}/*'
                  - !Sub '${organizationPrincipalId}/${organizationRootOuId}/${sandboxOuId}/*'
      Policies:
        - PolicyName: AppConfigAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - appconfig:GetConfiguration
                  - appconfig:StartConfigurationSession
                  - appconfig:GetLatestConfiguration
                Resource: !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}/environment/${DevEnvironment}/configuration/*'
              - Effect: Allow
                Action:
                  - appconfig:GetApplication
                  - appconfig:GetEnvironment
                  - appconfig:GetConfigurationProfile
                  - appconfig:ListApplications
                  - appconfig:ListConfigurationProfiles
                  - appconfig:ListEnvironments
                  - appconfig:ListHostedConfigurationVersions
                Resource: 
                  - !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}'
                  - !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}/environment/*'
                  - !Sub 'arn:aws:appconfig:*:${AWS::AccountId}:application/${Application}/configurationprofile/*'

  # SSM Parameters - Created in Production Accounts
  ProdAppConfigRoleParameter:
    Type: AWS::SSM::Parameter
    OrganizationBinding: !Ref ProdParametersBinding
    Properties:
      Name: !Sub '/appconfig/${applicationName}/role-name'
      Type: String
      Value: !Sub 'appconfig-${applicationName}-prod'
      Description: !Sub 'Cross-account role name for ${applicationName} AppConfig access'

  ProdAppConfigRoleArnParameter:
    Type: AWS::SSM::Parameter
    OrganizationBinding: !Ref ProdParametersBinding
    Properties:
      Name: !Sub '/appconfig/${applicationName}/role-arn'
      Type: String
      Value: !Sub 'arn:aws:iam::${appConfigAccountId}:role/appconfig-${applicationName}-prod'
      Description: !Sub 'Cross-account role ARN for ${applicationName} AppConfig access'

  ProdAppConfigEnvironmentParameter:
    Type: AWS::SSM::Parameter
    OrganizationBinding: !Ref ProdParametersBinding
    Properties:
      Name: !Sub '/appconfig/${applicationName}/environment-id'
      Type: String
      Value: !Ref ProdEnvironment
      Description: !Sub 'AppConfig Environment ID for ${applicationName} Production environment'

  ProdAppConfigEnvironmentNameParameter:
    Type: AWS::SSM::Parameter
    OrganizationBinding: !Ref ProdParametersBinding
    Properties:
      Name: !Sub '/appconfig/${applicationName}/environment-name'
      Type: String
      Value: 'prod'
      Description: !Sub 'AppConfig Environment Name for ${applicationName} Production environment'

  # SSM Parameters - Created in Development Accounts
  DevAppConfigRoleParameter:
    Type: AWS::SSM::Parameter
    OrganizationBinding: !Ref DevParametersBinding
    Properties:
      Name: !Sub '/appconfig/${applicationName}/role-name'
      Type: String
      Value: !Sub 'appconfig-${applicationName}-dev'
      Description: !Sub 'Cross-account role name for ${applicationName} AppConfig access'

  DevAppConfigRoleArnParameter:
    Type: AWS::SSM::Parameter
    OrganizationBinding: !Ref DevParametersBinding
    Properties:
      Name: !Sub '/appconfig/${applicationName}/role-arn'
      Type: String
      Value: !Sub 'arn:aws:iam::${appConfigAccountId}:role/appconfig-${applicationName}-dev'
      Description: !Sub 'Cross-account role ARN for ${applicationName} AppConfig access'

  DevAppConfigEnvironmentParameter:
    Type: AWS::SSM::Parameter
    OrganizationBinding: !Ref DevParametersBinding
    Properties:
      Name: !Sub '/appconfig/${applicationName}/environment-id'
      Type: String
      Value: !Ref DevEnvironment
      Description: !Sub 'AppConfig Environment ID for ${applicationName} Development environment'

  DevAppConfigEnvironmentNameParameter:
    Type: AWS::SSM::Parameter
    OrganizationBinding: !Ref DevParametersBinding
    Properties:
      Name: !Sub '/appconfig/${applicationName}/environment-name'
      Type: String
      Value: 'dev'
      Description: !Sub 'AppConfig Environment Name for ${applicationName} Development environment'

Outputs:
  ApplicationId:
    Description: AppConfig Application ID
    Value: !Ref Application
    Export:
      Name: !Sub '${AWS::StackName}-application-id'

  ProdEnvironmentId:
    Description: Production Environment ID
    Value: !Ref ProdEnvironment
    Export:
      Name: !Sub '${AWS::StackName}-prod-env-id'

  DevEnvironmentId:
    Description: Development Environment ID
    Value: !Ref DevEnvironment
    Export:
      Name: !Sub '${AWS::StackName}-dev-env-id'

  ProdAccessRoleArn:
    Description: ARN of the Production access role
    Value: !GetAtt ProdAccessRole.Arn
    Export:
      Name: !Sub '${AWS::StackName}-prod-role-arn'

  DevAccessRoleArn:
    Description: ARN of the SDLC access role
    Value: !GetAtt DevAccessRole.Arn
    Export:
      Name: !Sub '${AWS::StackName}-dev-role-arn' 
Enter fullscreen mode Exit fullscreen mode

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more