Repository: aws-samples/cdk-keycloak (language: python)

Issue:
Request an API to add custom env
https://github.com/aws-samples/cdk-keycloak/blob/d543239e3833c4374abe918eaa321d2da91052da/src/keycloak.ts#L486-L492


Discussion / hints:

Fix patch:
diff --git a/API.md b/API.md
index 01dd28b..c9f4710 100644
--- a/API.md
+++ b/API.md
@@ -47,6 +47,7 @@ new ContainerService(scope: Construct, id: string, props: ContainerServiceProps)
   * **autoScaleTask** (<code>[AutoScaleTask](#cdk-keycloak-autoscaletask)</code>)  Autoscaling for the ECS Service. __*Default*__: no ecs service autoscaling
   * **bastion** (<code>boolean</code>)  Whether to create the bastion host. __*Default*__: false
   * **circuitBreaker** (<code>boolean</code>)  Whether to enable the ECS service deployment circuit breaker. __*Default*__: false
+  * **env** (<code>Map<string, string></code>)  The environment variables to pass to the keycloak container. __*Optional*__
   * **nodeCount** (<code>number</code>)  Number of keycloak node in the cluster. __*Default*__: 1
   * **privateSubnets** (<code>[SubnetSelection](#aws-cdk-aws-ec2-subnetselection)</code>)  VPC subnets for keycloak service. __*Optional*__
   * **publicSubnets** (<code>[SubnetSelection](#aws-cdk-aws-ec2-subnetselection)</code>)  VPC public subnets for ALB. __*Optional*__
@@ -133,6 +134,7 @@ new KeyCloak(scope: Construct, id: string, props: KeyCloakProps)
   * **clusterEngine** (<code>[IClusterEngine](#aws-cdk-aws-rds-iclusterengine)</code>)  The database cluster engine. __*Default*__: rds.AuroraMysqlEngineVersion.VER_2_09_1
   * **databaseInstanceType** (<code>[InstanceType](#aws-cdk-aws-ec2-instancetype)</code>)  Database instance type. __*Default*__: r5.large
   * **databaseSubnets** (<code>[SubnetSelection](#aws-cdk-aws-ec2-subnetselection)</code>)  VPC subnets for database. __*Default*__: VPC isolated subnets
+  * **env** (<code>Map<string, string></code>)  The environment variables to pass to the keycloak container. __*Optional*__
   * **instanceEngine** (<code>[IInstanceEngine](#aws-cdk-aws-rds-iinstanceengine)</code>)  The database instance engine. __*Default*__: MySQL 8.0.21
   * **nodeCount** (<code>number</code>)  Number of keycloak node in the cluster. __*Default*__: 2
   * **privateSubnets** (<code>[SubnetSelection](#aws-cdk-aws-ec2-subnetselection)</code>)  VPC private subnets for keycloak service. __*Default*__: VPC private subnets
@@ -191,6 +193,7 @@ addKeyCloakContainerService(props: ContainerServiceProps): ContainerService
   * **autoScaleTask** (<code>[AutoScaleTask](#cdk-keycloak-autoscaletask)</code>)  Autoscaling for the ECS Service. __*Default*__: no ecs service autoscaling
   * **bastion** (<code>boolean</code>)  Whether to create the bastion host. __*Default*__: false
   * **circuitBreaker** (<code>boolean</code>)  Whether to enable the ECS service deployment circuit breaker. __*Default*__: false
+  * **env** (<code>Map<string, string></code>)  The environment variables to pass to the keycloak container. __*Optional*__
   * **nodeCount** (<code>number</code>)  Number of keycloak node in the cluster. __*Default*__: 1
   * **privateSubnets** (<code>[SubnetSelection](#aws-cdk-aws-ec2-subnetselection)</code>)  VPC subnets for keycloak service. __*Optional*__
   * **publicSubnets** (<code>[SubnetSelection](#aws-cdk-aws-ec2-subnetselection)</code>)  VPC public subnets for ALB. __*Optional*__
@@ -232,6 +235,7 @@ Name | Type | Description
 **autoScaleTask**? | <code>[AutoScaleTask](#cdk-keycloak-autoscaletask)</code> | Autoscaling for the ECS Service.<br/>__*Default*__: no ecs service autoscaling
 **bastion**? | <code>boolean</code> | Whether to create the bastion host.<br/>__*Default*__: false
 **circuitBreaker**? | <code>boolean</code> | Whether to enable the ECS service deployment circuit breaker.<br/>__*Default*__: false
+**env**? | <code>Map<string, string></code> | The environment variables to pass to the keycloak container.<br/>__*Optional*__
 **nodeCount**? | <code>number</code> | Number of keycloak node in the cluster.<br/>__*Default*__: 1
 **privateSubnets**? | <code>[SubnetSelection](#aws-cdk-aws-ec2-subnetselection)</code> | VPC subnets for keycloak service.<br/>__*Optional*__
 **publicSubnets**? | <code>[SubnetSelection](#aws-cdk-aws-ec2-subnetselection)</code> | VPC public subnets for ALB.<br/>__*Optional*__
@@ -292,6 +296,7 @@ Name | Type | Description
 **clusterEngine**? | <code>[IClusterEngine](#aws-cdk-aws-rds-iclusterengine)</code> | The database cluster engine.<br/>__*Default*__: rds.AuroraMysqlEngineVersion.VER_2_09_1
 **databaseInstanceType**? | <code>[InstanceType](#aws-cdk-aws-ec2-instancetype)</code> | Database instance type.<br/>__*Default*__: r5.large
 **databaseSubnets**? | <code>[SubnetSelection](#aws-cdk-aws-ec2-subnetselection)</code> | VPC subnets for database.<br/>__*Default*__: VPC isolated subnets
+**env**? | <code>Map<string, string></code> | The environment variables to pass to the keycloak container.<br/>__*Optional*__
 **instanceEngine**? | <code>[IInstanceEngine](#aws-cdk-aws-rds-iinstanceengine)</code> | The database instance engine.<br/>__*Default*__: MySQL 8.0.21
 **nodeCount**? | <code>number</code> | Number of keycloak node in the cluster.<br/>__*Default*__: 2
 **privateSubnets**? | <code>[SubnetSelection](#aws-cdk-aws-ec2-subnetselection)</code> | VPC private subnets for keycloak service.<br/>__*Default*__: VPC private subnets
diff --git a/src/keycloak.ts b/src/keycloak.ts
index bdfb524..1e19607 100644
--- a/src/keycloak.ts
+++ b/src/keycloak.ts
@@ -71,6 +71,10 @@ export interface AutoScaleTask {
 }
 
 export interface KeyCloakProps {
+  /**
+   * The environment variables to pass to the keycloak container
+   */
+  readonly env?: { [key: string]: string };
   /**
    * VPC for the workload
    */
@@ -196,6 +200,7 @@ export class KeyCloak extends cdk.Construct {
       nodeCount: props.nodeCount,
       stickinessCookieDuration: props.stickinessCookieDuration,
       autoScaleTask: props.autoScaleTask,
+      env: props.env,
     });
   }
   public addDatabase(props: DatabaseProps): Database {
@@ -381,6 +386,10 @@ export class Database extends cdk.Construct {
 }
 
 export interface ContainerServiceProps {
+  /**
+   * The environment variables to pass to the keycloak container
+   */
+  readonly env?: { [key: string]: string };
   /**
    * The VPC for the service
    */
@@ -483,14 +492,14 @@ export class ContainerService extends cdk.Construct {
     });
     const kc = taskDefinition.addContainer('keycloak', {
       image: ecs.ContainerImage.fromRegistry(this.getKeyCloakDockerImageUri()),
-      environment: {
+      environment: Object.assign({
         DB_ADDR: props.database.clusterEndpointHostname,
         DB_DATABASE: 'keycloak',
         DB_PORT: '3306',
         DB_USER: 'admin',
         DB_VENDOR: 'mysql',
         JDBC_PARAMS: 'useSSL=false',
-      },
+      }, props.env),
       secrets: {
         DB_PASSWORD: ecs.Secret.fromSecretsManager(props.database.secret, 'password'),
         KEYCLOAK_USER: ecs.Secret.fromSecretsManager(props.keycloakSecret, 'username'),


Test patch:
diff --git a/test/cluster.test.ts b/test/cluster.test.ts
index f7d53bd..f38c5b9 100644
--- a/test/cluster.test.ts
+++ b/test/cluster.test.ts
@@ -266,3 +266,204 @@ test('with single rds instance', () => {
     },
   });
 });
+
+test('with env', () => {
+  // GIVEN
+  const app = new App();
+  const stack = new Stack(app, 'testing-stack');
+
+  // WHEN
+  new kc.KeyCloak(stack, 'KeyCloak', {
+    certificateArn: 'MOCK_ARN',
+    env: {
+      JAVA_OPTS: '-DHelloWorld',
+    },
+  });
+
+  // THEN
+  expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', {
+    ContainerDefinitions: [
+      {
+        Command: [
+          'sh',
+          '-c',
+          'mysql -u$DB_USER -p$DB_PASSWORD -h$DB_ADDR -e "CREATE DATABASE IF NOT EXISTS $DB_NAME"',
+        ],
+        Environment: [
+          {
+            Name: 'DB_NAME',
+            Value: 'keycloak',
+          },
+          {
+            Name: 'DB_USER',
+            Value: 'admin',
+          },
+          {
+            Name: 'DB_ADDR',
+            Value: {
+              'Fn::GetAtt': [
+                'KeyCloakDatabaseDBCluster06E9C0E1',
+                'Endpoint.Address',
+              ],
+            },
+          },
+        ],
+        Essential: false,
+        Image: {
+          'Fn::FindInMap': [
+            'KeyCloakKeyCloakContainerSerivceBootstrapImageMap1F3D33FC',
+            {
+              Ref: 'AWS::Partition',
+            },
+            'uri',
+          ],
+        },
+        LogConfiguration: {
+          LogDriver: 'awslogs',
+          Options: {
+            'awslogs-group': {
+              Ref: 'KeyCloakKeyCloakContainerSerivceLogGroup010F2AAE',
+            },
+            'awslogs-stream-prefix': 'bootstrap',
+            'awslogs-region': {
+              Ref: 'AWS::Region',
+            },
+          },
+        },
+        Name: 'bootstrap',
+        Secrets: [
+          {
+            Name: 'DB_PASSWORD',
+            ValueFrom: {
+              'Fn::Join': [
+                '',
+                [
+                  {
+                    Ref: 'KeyCloakDatabaseDBClusterSecretAttachment50401C92',
+                  },
+                  ':password::',
+                ],
+              ],
+            },
+          },
+        ],
+      },
+      {
+        DependsOn: [
+          {
+            Condition: 'SUCCESS',
+            ContainerName: 'bootstrap',
+          },
+        ],
+        Environment: [
+          {
+            Name: 'DB_ADDR',
+            Value: {
+              'Fn::GetAtt': [
+                'KeyCloakDatabaseDBCluster06E9C0E1',
+                'Endpoint.Address',
+              ],
+            },
+          },
+          {
+            Name: 'DB_DATABASE',
+            Value: 'keycloak',
+          },
+          {
+            Name: 'DB_PORT',
+            Value: '3306',
+          },
+          {
+            Name: 'DB_USER',
+            Value: 'admin',
+          },
+          {
+            Name: 'DB_VENDOR',
+            Value: 'mysql',
+          },
+          {
+            Name: 'JDBC_PARAMS',
+            Value: 'useSSL=false',
+          },
+          {
+            Name: 'JAVA_OPTS',
+            Value: '-DHelloWorld',
+          },
+        ],
+        Essential: true,
+        Image: {
+          'Fn::FindInMap': [
+            'KeyCloakKeyCloakContainerSerivceKeycloakImageMapF79EAEA3',
+            {
+              Ref: 'AWS::Partition',
+            },
+            'uri',
+          ],
+        },
+        LogConfiguration: {
+          LogDriver: 'awslogs',
+          Options: {
+            'awslogs-group': {
+              Ref: 'KeyCloakKeyCloakContainerSerivceLogGroup010F2AAE',
+            },
+            'awslogs-stream-prefix': 'keycloak',
+            'awslogs-region': {
+              Ref: 'AWS::Region',
+            },
+          },
+        },
+        Name: 'keycloak',
+        PortMappings: [
+          {
+            ContainerPort: 8443,
+            Protocol: 'tcp',
+          },
+        ],
+        Secrets: [
+          {
+            Name: 'DB_PASSWORD',
+            ValueFrom: {
+              'Fn::Join': [
+                '',
+                [
+                  {
+                    Ref: 'KeyCloakDatabaseDBClusterSecretAttachment50401C92',
+                  },
+                  ':password::',
+                ],
+              ],
+            },
+          },
+          {
+            Name: 'KEYCLOAK_USER',
+            ValueFrom: {
+              'Fn::Join': [
+                '',
+                [
+                  {
+                    Ref: 'KeyCloakKCSecretF8498E5C',
+                  },
+                  ':username::',
+                ],
+              ],
+            },
+          },
+          {
+            Name: 'KEYCLOAK_PASSWORD',
+            ValueFrom: {
+              'Fn::Join': [
+                '',
+                [
+                  {
+                    Ref: 'KeyCloakKCSecretF8498E5C',
+                  },
+                  ':password::',
+                ],
+              ],
+            },
+          },
+        ],
+      },
+    ],
+  });
+});