The aws:rds/customDbEngineVersion:CustomDbEngineVersion resource, part of the Pulumi AWS provider, registers custom engine versions (CEVs) for RDS Custom. CEVs define which Oracle installation files or SQL Server AMIs RDS Custom uses when creating database instances. This guide focuses on three capabilities: Oracle CEV creation with S3-stored files, SQL Server CEV creation from AMIs, and manifest management.
Oracle CEVs require S3 buckets containing installation files and KMS keys for encryption. SQL Server CEVs require operator-owned AMIs. The examples are intentionally small. Combine them with your own S3 buckets, KMS keys, or AMI preparation workflows.
Create an Oracle CEV with inline manifest
RDS Custom for Oracle requires a CEV that references database installation files stored in S3. The manifest lists which files to use during installation.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.kms.Key("example", {description: "KMS symmetric key for RDS Custom for Oracle"});
const exampleCustomDbEngineVersion = new aws.rds.CustomDbEngineVersion("example", {
databaseInstallationFilesS3BucketName: "DOC-EXAMPLE-BUCKET",
databaseInstallationFilesS3Prefix: "1915_GI/",
engine: "custom-oracle-ee-cdb",
engineVersion: "19.cdb_cev1",
kmsKeyId: example.arn,
manifest: ` {
\\t\\"databaseInstallationFileNames\\":[\\"V982063-01.zip\\"]
}
`,
tags: {
Name: "example",
Key: "value",
},
});
import pulumi
import pulumi_aws as aws
example = aws.kms.Key("example", description="KMS symmetric key for RDS Custom for Oracle")
example_custom_db_engine_version = aws.rds.CustomDbEngineVersion("example",
database_installation_files_s3_bucket_name="DOC-EXAMPLE-BUCKET",
database_installation_files_s3_prefix="1915_GI/",
engine="custom-oracle-ee-cdb",
engine_version="19.cdb_cev1",
kms_key_id=example.arn,
manifest=""" {
\t\"databaseInstallationFileNames\":[\"V982063-01.zip\"]
}
""",
tags={
"Name": "example",
"Key": "value",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/kms"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := kms.NewKey(ctx, "example", &kms.KeyArgs{
Description: pulumi.String("KMS symmetric key for RDS Custom for Oracle"),
})
if err != nil {
return err
}
_, err = rds.NewCustomDbEngineVersion(ctx, "example", &rds.CustomDbEngineVersionArgs{
DatabaseInstallationFilesS3BucketName: pulumi.String("DOC-EXAMPLE-BUCKET"),
DatabaseInstallationFilesS3Prefix: pulumi.String("1915_GI/"),
Engine: pulumi.String("custom-oracle-ee-cdb"),
EngineVersion: pulumi.String("19.cdb_cev1"),
KmsKeyId: example.Arn,
Manifest: pulumi.String(" {\n\\t\\\"databaseInstallationFileNames\\\":[\\\"V982063-01.zip\\\"]\n }\n"),
Tags: pulumi.StringMap{
"Name": pulumi.String("example"),
"Key": pulumi.String("value"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Kms.Key("example", new()
{
Description = "KMS symmetric key for RDS Custom for Oracle",
});
var exampleCustomDbEngineVersion = new Aws.Rds.CustomDbEngineVersion("example", new()
{
DatabaseInstallationFilesS3BucketName = "DOC-EXAMPLE-BUCKET",
DatabaseInstallationFilesS3Prefix = "1915_GI/",
Engine = "custom-oracle-ee-cdb",
EngineVersion = "19.cdb_cev1",
KmsKeyId = example.Arn,
Manifest = @" {
\t\""databaseInstallationFileNames\"":[\""V982063-01.zip\""]
}
",
Tags =
{
{ "Name", "example" },
{ "Key", "value" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.kms.Key;
import com.pulumi.aws.kms.KeyArgs;
import com.pulumi.aws.rds.CustomDbEngineVersion;
import com.pulumi.aws.rds.CustomDbEngineVersionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Key("example", KeyArgs.builder()
.description("KMS symmetric key for RDS Custom for Oracle")
.build());
var exampleCustomDbEngineVersion = new CustomDbEngineVersion("exampleCustomDbEngineVersion", CustomDbEngineVersionArgs.builder()
.databaseInstallationFilesS3BucketName("DOC-EXAMPLE-BUCKET")
.databaseInstallationFilesS3Prefix("1915_GI/")
.engine("custom-oracle-ee-cdb")
.engineVersion("19.cdb_cev1")
.kmsKeyId(example.arn())
.manifest("""
{
\t\"databaseInstallationFileNames\":[\"V982063-01.zip\"]
}
""")
.tags(Map.ofEntries(
Map.entry("Name", "example"),
Map.entry("Key", "value")
))
.build());
}
}
resources:
example:
type: aws:kms:Key
properties:
description: KMS symmetric key for RDS Custom for Oracle
exampleCustomDbEngineVersion:
type: aws:rds:CustomDbEngineVersion
name: example
properties:
databaseInstallationFilesS3BucketName: DOC-EXAMPLE-BUCKET
databaseInstallationFilesS3Prefix: 1915_GI/
engine: custom-oracle-ee-cdb
engineVersion: 19.cdb_cev1
kmsKeyId: ${example.arn}
manifest: |2
{
\t\"databaseInstallationFileNames\":[\"V982063-01.zip\"]
}
tags:
Name: example
Key: value
The engine and engineVersion properties identify this CEV uniquely. The databaseInstallationFilesS3BucketName and databaseInstallationFilesS3Prefix point to your Oracle installation files in S3. The manifest property contains JSON that lists specific installation file names. The kmsKeyId grants RDS Custom permission to decrypt the installation files.
Reference an external manifest file for Oracle
When manifest content is managed separately from infrastructure code, you can reference an external JSON file and track changes via hash.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as std from "@pulumi/std";
const example = new aws.kms.Key("example", {description: "KMS symmetric key for RDS Custom for Oracle"});
const exampleCustomDbEngineVersion = new aws.rds.CustomDbEngineVersion("example", {
databaseInstallationFilesS3BucketName: "DOC-EXAMPLE-BUCKET",
databaseInstallationFilesS3Prefix: "1915_GI/",
engine: "custom-oracle-ee-cdb",
engineVersion: "19.cdb_cev1",
kmsKeyId: example.arn,
filename: "manifest_1915_GI.json",
manifestHash: std.filebase64sha256({
input: json,
}).then(invoke => invoke.result),
tags: {
Name: "example",
Key: "value",
},
});
import pulumi
import pulumi_aws as aws
import pulumi_std as std
example = aws.kms.Key("example", description="KMS symmetric key for RDS Custom for Oracle")
example_custom_db_engine_version = aws.rds.CustomDbEngineVersion("example",
database_installation_files_s3_bucket_name="DOC-EXAMPLE-BUCKET",
database_installation_files_s3_prefix="1915_GI/",
engine="custom-oracle-ee-cdb",
engine_version="19.cdb_cev1",
kms_key_id=example.arn,
filename="manifest_1915_GI.json",
manifest_hash=std.filebase64sha256(input=json).result,
tags={
"Name": "example",
"Key": "value",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/kms"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
"github.com/pulumi/pulumi-std/sdk/go/std"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := kms.NewKey(ctx, "example", &kms.KeyArgs{
Description: pulumi.String("KMS symmetric key for RDS Custom for Oracle"),
})
if err != nil {
return err
}
invokeFilebase64sha256, err := std.Filebase64sha256(ctx, &std.Filebase64sha256Args{
Input: json,
}, nil)
if err != nil {
return err
}
_, err = rds.NewCustomDbEngineVersion(ctx, "example", &rds.CustomDbEngineVersionArgs{
DatabaseInstallationFilesS3BucketName: pulumi.String("DOC-EXAMPLE-BUCKET"),
DatabaseInstallationFilesS3Prefix: pulumi.String("1915_GI/"),
Engine: pulumi.String("custom-oracle-ee-cdb"),
EngineVersion: pulumi.String("19.cdb_cev1"),
KmsKeyId: example.Arn,
Filename: pulumi.String("manifest_1915_GI.json"),
ManifestHash: pulumi.String(invokeFilebase64sha256.Result),
Tags: pulumi.StringMap{
"Name": pulumi.String("example"),
"Key": pulumi.String("value"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Kms.Key("example", new()
{
Description = "KMS symmetric key for RDS Custom for Oracle",
});
var exampleCustomDbEngineVersion = new Aws.Rds.CustomDbEngineVersion("example", new()
{
DatabaseInstallationFilesS3BucketName = "DOC-EXAMPLE-BUCKET",
DatabaseInstallationFilesS3Prefix = "1915_GI/",
Engine = "custom-oracle-ee-cdb",
EngineVersion = "19.cdb_cev1",
KmsKeyId = example.Arn,
Filename = "manifest_1915_GI.json",
ManifestHash = Std.Filebase64sha256.Invoke(new()
{
Input = json,
}).Apply(invoke => invoke.Result),
Tags =
{
{ "Name", "example" },
{ "Key", "value" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.kms.Key;
import com.pulumi.aws.kms.KeyArgs;
import com.pulumi.aws.rds.CustomDbEngineVersion;
import com.pulumi.aws.rds.CustomDbEngineVersionArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.Filebase64sha256Args;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Key("example", KeyArgs.builder()
.description("KMS symmetric key for RDS Custom for Oracle")
.build());
var exampleCustomDbEngineVersion = new CustomDbEngineVersion("exampleCustomDbEngineVersion", CustomDbEngineVersionArgs.builder()
.databaseInstallationFilesS3BucketName("DOC-EXAMPLE-BUCKET")
.databaseInstallationFilesS3Prefix("1915_GI/")
.engine("custom-oracle-ee-cdb")
.engineVersion("19.cdb_cev1")
.kmsKeyId(example.arn())
.filename("manifest_1915_GI.json")
.manifestHash(StdFunctions.filebase64sha256(Filebase64sha256Args.builder()
.input(json)
.build()).result())
.tags(Map.ofEntries(
Map.entry("Name", "example"),
Map.entry("Key", "value")
))
.build());
}
}
resources:
example:
type: aws:kms:Key
properties:
description: KMS symmetric key for RDS Custom for Oracle
exampleCustomDbEngineVersion:
type: aws:rds:CustomDbEngineVersion
name: example
properties:
databaseInstallationFilesS3BucketName: DOC-EXAMPLE-BUCKET
databaseInstallationFilesS3Prefix: 1915_GI/
engine: custom-oracle-ee-cdb
engineVersion: 19.cdb_cev1
kmsKeyId: ${example.arn}
filename: manifest_1915_GI.json
manifestHash:
fn::invoke:
function: std:filebase64sha256
arguments:
input: ${json}
return: result
tags:
Name: example
Key: value
The filename property points to a local manifest file instead of embedding JSON inline. The manifestHash property triggers updates when the manifest changes; use filebase64sha256 to compute the hash automatically. This approach separates manifest content from infrastructure definitions, making it easier to version control large or frequently changing manifests.
Create a SQL Server CEV from an AMI
RDS Custom for SQL Server builds engine versions from AMIs rather than S3-stored files. You must own the source AMI in your account.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// CEV creation requires an AMI owned by the operator
const test = new aws.rds.CustomDbEngineVersion("test", {
engine: "custom-sqlserver-se",
engineVersion: "15.00.4249.2.cev-1",
sourceImageId: "ami-0aa12345678a12ab1",
});
import pulumi
import pulumi_aws as aws
# CEV creation requires an AMI owned by the operator
test = aws.rds.CustomDbEngineVersion("test",
engine="custom-sqlserver-se",
engine_version="15.00.4249.2.cev-1",
source_image_id="ami-0aa12345678a12ab1")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// CEV creation requires an AMI owned by the operator
_, err := rds.NewCustomDbEngineVersion(ctx, "test", &rds.CustomDbEngineVersionArgs{
Engine: pulumi.String("custom-sqlserver-se"),
EngineVersion: pulumi.String("15.00.4249.2.cev-1"),
SourceImageId: pulumi.String("ami-0aa12345678a12ab1"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
// CEV creation requires an AMI owned by the operator
var test = new Aws.Rds.CustomDbEngineVersion("test", new()
{
Engine = "custom-sqlserver-se",
EngineVersion = "15.00.4249.2.cev-1",
SourceImageId = "ami-0aa12345678a12ab1",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.CustomDbEngineVersion;
import com.pulumi.aws.rds.CustomDbEngineVersionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
// CEV creation requires an AMI owned by the operator
var test = new CustomDbEngineVersion("test", CustomDbEngineVersionArgs.builder()
.engine("custom-sqlserver-se")
.engineVersion("15.00.4249.2.cev-1")
.sourceImageId("ami-0aa12345678a12ab1")
.build());
}
}
resources:
# CEV creation requires an AMI owned by the operator
test:
type: aws:rds:CustomDbEngineVersion
properties:
engine: custom-sqlserver-se
engineVersion: 15.00.4249.2.cev-1
sourceImageId: ami-0aa12345678a12ab1
The sourceImageId property references an AMI you own. Unlike Oracle CEVs, SQL Server doesn’t use S3 buckets or KMS keys; the AMI contains the complete SQL Server installation. You cannot use AWS-owned AMIs; you must create or copy the AMI into your account first.
Copy an AMI across regions for SQL Server
When your SQL Server AMI exists in a different region, you must copy it to the target region before creating the CEV.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.ec2.AmiCopy("example", {
name: "sqlserver-se-2019-15.00.4249.2",
description: "A copy of ami-xxxxxxxx",
sourceAmiId: "ami-xxxxxxxx",
sourceAmiRegion: "us-east-1",
});
// CEV creation requires an AMI owned by the operator
const test = new aws.rds.CustomDbEngineVersion("test", {
engine: "custom-sqlserver-se",
engineVersion: "15.00.4249.2.cev-1",
sourceImageId: example.id,
});
import pulumi
import pulumi_aws as aws
example = aws.ec2.AmiCopy("example",
name="sqlserver-se-2019-15.00.4249.2",
description="A copy of ami-xxxxxxxx",
source_ami_id="ami-xxxxxxxx",
source_ami_region="us-east-1")
# CEV creation requires an AMI owned by the operator
test = aws.rds.CustomDbEngineVersion("test",
engine="custom-sqlserver-se",
engine_version="15.00.4249.2.cev-1",
source_image_id=example.id)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := ec2.NewAmiCopy(ctx, "example", &ec2.AmiCopyArgs{
Name: pulumi.String("sqlserver-se-2019-15.00.4249.2"),
Description: pulumi.String("A copy of ami-xxxxxxxx"),
SourceAmiId: pulumi.String("ami-xxxxxxxx"),
SourceAmiRegion: pulumi.String("us-east-1"),
})
if err != nil {
return err
}
// CEV creation requires an AMI owned by the operator
_, err = rds.NewCustomDbEngineVersion(ctx, "test", &rds.CustomDbEngineVersionArgs{
Engine: pulumi.String("custom-sqlserver-se"),
EngineVersion: pulumi.String("15.00.4249.2.cev-1"),
SourceImageId: example.ID(),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Ec2.AmiCopy("example", new()
{
Name = "sqlserver-se-2019-15.00.4249.2",
Description = "A copy of ami-xxxxxxxx",
SourceAmiId = "ami-xxxxxxxx",
SourceAmiRegion = "us-east-1",
});
// CEV creation requires an AMI owned by the operator
var test = new Aws.Rds.CustomDbEngineVersion("test", new()
{
Engine = "custom-sqlserver-se",
EngineVersion = "15.00.4249.2.cev-1",
SourceImageId = example.Id,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.AmiCopy;
import com.pulumi.aws.ec2.AmiCopyArgs;
import com.pulumi.aws.rds.CustomDbEngineVersion;
import com.pulumi.aws.rds.CustomDbEngineVersionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new AmiCopy("example", AmiCopyArgs.builder()
.name("sqlserver-se-2019-15.00.4249.2")
.description("A copy of ami-xxxxxxxx")
.sourceAmiId("ami-xxxxxxxx")
.sourceAmiRegion("us-east-1")
.build());
// CEV creation requires an AMI owned by the operator
var test = new CustomDbEngineVersion("test", CustomDbEngineVersionArgs.builder()
.engine("custom-sqlserver-se")
.engineVersion("15.00.4249.2.cev-1")
.sourceImageId(example.id())
.build());
}
}
resources:
example:
type: aws:ec2:AmiCopy
properties:
name: sqlserver-se-2019-15.00.4249.2
description: A copy of ami-xxxxxxxx
sourceAmiId: ami-xxxxxxxx
sourceAmiRegion: us-east-1
# CEV creation requires an AMI owned by the operator
test:
type: aws:rds:CustomDbEngineVersion
properties:
engine: custom-sqlserver-se
engineVersion: 15.00.4249.2.cev-1
sourceImageId: ${example.id}
The AmiCopy resource copies an AMI from sourceAmiRegion to your target region. The CEV then references the copied AMI’s ID. This pattern is necessary because CEVs can only reference AMIs in the same region where the CEV is created.
Beyond these examples
These snippets focus on specific CEV registration features: Oracle CEV creation with S3-stored installation files, SQL Server CEV creation from AMIs, and manifest management. They’re intentionally minimal rather than full RDS Custom deployments.
The examples rely on pre-existing infrastructure such as S3 buckets with Oracle installation files, KMS keys for encryption, and AMIs for SQL Server owned by the operator. They focus on registering the CEV rather than provisioning the surrounding infrastructure.
To keep things focused, common CEV patterns are omitted, including:
- CEV lifecycle management (status transitions)
- Cross-region AMI copying automation
- Manifest validation and error handling
- IAM permissions for RDS Custom operations
These omissions are intentional: the goal is to illustrate how each CEV type is wired, not provide drop-in RDS Custom modules. See the Custom DB Engine Version resource reference for all available configuration options.
Let's configure AWS RDS Custom Database Engine Versions
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Oracle vs SQL Server Requirements
kmsKeyId, databaseInstallationFilesS3BucketName, databaseInstallationFilesS3Prefix, and a manifest (via manifest or filename). SQL Server CEVs require sourceImageId pointing to an AMI you own, with no KMS key or S3 bucket needed.kmsKeyId. SQL Server CEVs do not use KMS encryption for installation files.Manifest Configuration
manifest for inline JSON or filename to reference an external file. These properties conflict with each other, so choose one. Use filename with manifestHash if you need to trigger updates when the manifest changes.manifestComputed output is service-generated and often differs from your input manifest. Use manifestComputed to see the actual manifest AWS is using.manifestHash to the base64-encoded SHA256 hash of your updated manifest file using filebase64sha256("manifest.json"). This triggers Pulumi to detect the change.Immutability & Updates
engine, engineVersion, kmsKeyId, sourceImageId, manifest, filename, databaseInstallationFilesS3BucketName, and databaseInstallationFilesS3Prefix. Changing any of these requires replacing the resource.status values are available, inactive, and inactive-except-restore.AMI & Image Management
aws.ec2.AmiCopy, then reference the copied AMI’s ID in sourceImageId.sourceImageId that was used in a different Oracle CEV.