The aws:rds/customDbEngineVersion:CustomDbEngineVersion resource, part of the Pulumi AWS provider, registers custom engine versions (CEVs) for RDS Custom, defining the database software configuration for Oracle or SQL Server instances. This guide focuses on three capabilities: Oracle CEV creation with S3-stored installation files, SQL Server CEV creation from AMIs, and manifest management approaches.
CEVs have different requirements by engine type. Oracle CEVs require S3 buckets with 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 a CEV for Oracle with inline manifest
RDS Custom for Oracle requires a CEV that references database installation files stored in S3. Teams define the CEV with an inline JSON manifest listing the installation files.
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 the Oracle edition and version. The databaseInstallationFilesS3BucketName and databaseInstallationFilesS3Prefix point to where Oracle installation ZIPs are stored. The manifest property contains a JSON document listing the installation file names. The kmsKeyId encrypts the database installation files, required for Oracle CEVs.
Reference an external manifest file with change detection
When manifest content changes frequently or is managed separately from infrastructure code, teams store the manifest as a file and use hash-based change detection.
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 CEV updates when the manifest changes; filebase64sha256 computes the hash automatically. This approach separates manifest content from infrastructure code, making it easier to version and review changes independently.
Create a CEV for SQL Server from an AMI
RDS Custom for SQL Server builds custom engine versions from AMIs rather than S3-stored installation files. Teams must own the source AMI in their 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 that contains the SQL Server installation. Unlike Oracle CEVs, SQL Server doesn’t use S3 buckets, KMS keys, or manifest files. The AMI must be owned by the operator’s AWS account; shared or marketplace AMIs won’t work.
Copy an AMI across regions for SQL Server CEV
When the source AMI exists in a different region, teams 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 duplicates an AMI from one region to another. The sourceAmiId and sourceAmiRegion identify the original AMI location. Once copied, the new AMI ID is passed to the CEV’s sourceImageId property. This ensures the AMI is available in the region where the database will run.
Beyond these examples
These snippets focus on specific CEV-level 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 database deployment workflows.
The examples may reference pre-existing infrastructure such as S3 buckets with Oracle installation files, KMS keys for encryption (Oracle only), and AMIs owned by the operator (SQL Server only). 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)
- CEV descriptions and tagging strategies
- Cross-region CEV replication
- AMI preparation and validation
These omissions are intentional: the goal is to illustrate how each CEV feature is wired, not provide drop-in database 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
Configuration & Requirements
kmsKeyId, databaseInstallationFilesS3BucketName, and a manifest or filename. SQL Server CEVs require sourceImageId (an AMI you own) instead of KMS and S3 parameters.manifest and filename are mutually exclusive. Use inline manifest for JSON strings or filename for external files, but not both.Manifest Management
manifestHash to the base64-encoded SHA256 hash of your manifest file using filebase64sha256("manifest.json"). Without this, changes won’t trigger updates.manifestComputed output is service-generated and often differs from your input manifest. Use manifestComputed for reference after creation.AMI & Images
sourceImageId pointing to an AMI owned by your AWS account.aws.ec2.AmiCopy, then reference the copied AMI’s ID in sourceImageId.Lifecycle & Immutability
engine, engineVersion, kmsKeyId, sourceImageId, manifest, filename, databaseInstallationFilesS3BucketName, and databaseInstallationFilesS3Prefix.status values are available, inactive, and inactive-except-restore.