Generated banner for Dms Schema Conversion
Generated logo for Dms Schema Conversion

Dms Schema Conversion

AWSOfficialPublished by AWS

  • Skill
  • Workflow
  • Cloud and DevOps
  • Apache-2.0
  • No issues found

From the author

Handles the full DMS Schema Conversion lifecycle including creating migration projects, converting database schemas to a target engine, running compatibility assessments, navigating metadata trees, exporting converted DDL to S3, applying schema changes to a target database, and converting SQL statements between database engines. Applies when migrating database schemas between heterogeneous engines using AWS DMS Schema Conversion.
— the description by AWS

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a comprehensive workflow for migrating database schemas between heterogeneous engines using AWS DMS Schema Conversion. It guides users through the entire lifecycle, including project setup, metadata import, compatibility assessment, schema conversion, and applying changes to target databases. The skill includes built-in support for navigating metadata trees, generating conversion reports, and resolving action items identified during the assessment process.

What it does

  • Automates the creation and management of AWS DMS migration projects.
  • Performs compatibility assessments to estimate migration effort and complexity.
  • Converts source database schemas to target engine formats.
  • Provides tools to navigate and inspect source and target metadata models.
  • Generates and interprets conversion assessment reports for actionable insights.
  • Applies converted schema changes directly to target databases.

When to use it

  • When planning or executing a database migration between different database engines.
  • When you need to assess the complexity of a schema migration before committing to it.
  • When you need to convert specific SQL statements between database engines.
  • When you need to audit and resolve specific conversion issues identified by AWS DMS.

Advantages

  • Streamlines complex migration tasks into a repeatable, guided workflow.
  • Provides clear visibility into migration progress and potential compatibility issues.
  • Supports both automated conversion and manual intervention for complex objects.
  • Ensures consistent attribution of operations via standardized environment variables.

Usage examples

“I need to migrate my SQL Server schema to Aurora PostgreSQL. Can you help me set up a project?”
The agent will initiate the migration project setup wizard, guide you through data provider configuration, and perform an initial metadata import.
“Run a compatibility assessment for my 'sales' schema and show me the summary.”
The agent will build the necessary selection rules, trigger the assessment, download the summary report from S3, and present the object conversion statistics.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/aws/dms-schema-conversion/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip dms-schema-conversion.zip -d .agents/skills

Documentation by AWS

DMS Schema Conversion

Overview

This skill handles the full DMS Schema Conversion lifecycle — from first-time setup to running conversions on an existing project.

The AWS MCP server is recommended for streamlined execution, audit logging, and observability. When the MCP server is not available, all operations can be performed via AWS CLI directly.

Key documentation:

Global constraint: You MUST fetch and read any linked documentation before acting on it — do NOT rely on memory for any referenced material (selection rules, transformation rules, troubleshooting guides, network configuration, etc.). Documentation contains vendor-specific details that change between engines and API versions.


Guardrail — where this skill's own files live (MCP vs local install)

This skill can be loaded two ways, and they resolve the skill's own bundled files from different places. Determine how the skill was loaded before reading a reference:

  • Loaded through the AWS MCP retrieve_skill tool: The skill is not installed on the local filesystem. You MUST fetch each reference via retrieve_skill with the file parameter (e.g. file="references/setup-wizard.md"). Do NOT file_read these paths locally — they do not exist on disk.

  • Installed locally (e.g. .kiro/skills/dms-schema-conversion/ or ~/.claude/skills/dms-schema-conversion/): Read files from the local skill directory using relative paths.

This distinction applies only to the skill's own packaged files. User data and session artifacts are always read from and written to the user's working directory. Never fetch or write customer data through retrieve_skill.


Verify Dependencies

Before starting, check that AWS CLI commands can be executed.

Constraints:

  • You MUST verify that AWS CLI commands can be run (via MCP server tools or directly via shell)

  • You MUST inform the customer if no execution method is available and ask whether to proceed

  • You MUST ask the customer which AWS region to use — do NOT attempt to infer it from the STS response (it does not contain a region field). If the customer is unsure, suggest checking the AWS_DEFAULT_REGION environment variable or the --region flag they are using.

  • You MUST set the AWS_EXECUTION_ENV environment variable to AWSMCP-DMSSchemaConversion-Skill before running any AWS CLI command in this skill, so that calls made during this agentic workflow are attributable in the CloudTrail userAgent field. The AWS CLI and botocore append this value to the request User-Agent as exec-env/AWSMCP-DMSSchemaConversion-Skill. Set it once for the session (export AWS_EXECUTION_ENV=AWSMCP-DMSSchemaConversion-Skill) or prefix each command (AWS_EXECUTION_ENV=AWSMCP-DMSSchemaConversion-Skill aws dms ...). The value is a best-effort attribution marker only — it is not an access control, and it MUST contain no spaces so it stays a single User-Agent token.


Project Selection

Check for existing migration projects:

aws dms describe-migration-projects
  • If exactly one project exists → ask the customer: "Found migration project <name>. Would you like to use it, or create a new one?" If they confirm, store migration_project_identifier and proceed to Actions Menu. If they want a new one, run the setup wizard.

  • If multiple projects exist → list them and ask the customer to pick one, or offer to create a new project. Store migration_project_identifier, proceed to Actions Menu.

  • If no projects exist → ask: "No migration projects found. Would you like to create one?" If yes, load setup-wizard.md and run the full setup wizard from Phase 1. After wizard completes, run Auto Import, then proceed to Actions Menu.


Auto Import

This section runs only after the setup wizard creates a new project. Do NOT run for existing projects.

  1. Build selection rules to import all schemas from the source server. For server-name, use the data provider identifier (the short ID from the ARN, e.g., JIFET2LUZJEJZPDYSOSGANOA2M) or the literal ServerName value from the data provider settings (e.g., "offline" for offline sources). For SQL Server, you MUST include database-name in the object locator. See Selection rules in DMS Schema Conversion for JSON format.

  2. Run start-metadata-model-import with --origin SOURCE --refresh and the selection rules from step 1. Extract RequestIdentifier from the response.

  3. Wait for import completion using the DMS waiter:

    aws dms wait metadata-model-imported \
      --migration-project-identifier <migration_project_identifier> \
      --filter 'Name=schema-conversion-operation-id,Values=<RequestIdentifier>'

    If the waiter fails or is unavailable, fall back to polling describe-metadata-model-imports every 30 seconds with --filter Name=request-id,Values=<RequestIdentifier>. Terminal statuses: SUCCESS (proceed) or FAILED (check error via the Error field in the response).

  4. Show discovered schemas: On success, call describe-metadata-model-children with --origin SOURCE at the root level to list the imported schemas/databases. Present the discovered names to the customer so they can confirm the correct database connection was established:

    "Import complete. I found the following schemas/databases: <list>. Does this look correct?"

  5. Proceed to Actions Menu.


Actions Menu

Present the actions menu using a structured selection tool (e.g., AskUserQuestion) if available — this gives the customer a clickable/selectable list.

For SQL Server → PostgreSQL/Aurora PostgreSQL projects (present as a single-select question "What would you like to do?"):

  1. Convert database — convert schema objects to the target engine (also produces an conversion assessment report)

  2. Assess database — run a compatibility assessment (also produces an conversion assessment report)

  3. Convert statement — convert a single SQL statement

  4. Clean up — delete migration project and related DMS resources

For all other engine combinations (present as a single-select question "What would you like to do?"):

  1. Convert database — convert schema objects to the target engine (also produces an conversion assessment report)

  2. Assess database — run a compatibility assessment (also produces an conversion assessment report)

  3. Work with tree — browse the metadata model tree

  4. Clean up — delete migration project and related DMS resources

The customer can always type a custom request via "Other" (e.g., "work with tree", "show database statistics", or "exit"). If the customer selects "Other" and describes an action covered by this skill, handle it accordingly.

After each action completes, return to this menu by presenting the same selection again.

Note on metadata loading: start-metadata-model-import (with Refresh=false), start-metadata-model-assessment, and start-metadata-model-conversion all load the source tree for the scoped objects. If metadata was already imported in the current session for a given subtree, it does not need to be re-imported — these operations will work with what is already loaded.


Convert Database
  1. Ask what to convert: Ask the customer what they want to convert (e.g., "all schemas", "schema public", "tables starting with PROD_").

  2. Build selection rules: Translate the customer's natural language to selection rules JSON. Refer to Selection rules in DMS Schema Conversion for format, wildcards, and vendor-specific locators.

  3. Run conversion: Call start-metadata-model-conversion with the migration project and selection rules. Extract RequestIdentifier from the response.

  4. Wait for completion: Wait using the DMS waiter:

    aws dms wait metadata-model-converted \
      --migration-project-identifier <migration_project_identifier> \
      --filter 'Name=schema-conversion-operation-id,Values=<RequestIdentifier>'

    If the waiter fails or is unavailable, fall back to polling describe-metadata-model-conversions every 30 seconds with --filter Name=request-id,Values=<RequestIdentifier>. Terminal statuses: SUCCESS (proceed) or FAILED (check error).

  5. Export conversion assessment report: On conversion success, call export-metadata-model-assessment with selection rules using rule-action: "explicit" (this API requires explicit rules, not include). Provide the customer with S3 links for both PDF and CSV reports (PdfReport.S3ObjectKey and CsvReport.S3ObjectKey).

  6. Show summary: Download the Summary CSV from S3 using aws s3 cp s3://<bucket>/<CsvReport.S3ObjectKey> ./Summary.csv. Present its contents to the customer — show the number of objects per category, how many converted automatically, and how many have Action Items at each complexity level.

  7. Post-convert sub-menu: After showing the summary, present options. Only show "Apply to target" if the target is a live target (not virtual):

    "What would you like to do next?

    1. Fix Action Items — review and fix Action Items from the conversion assessment report

    2. Export as script — export converted DDL as SQL script to S3

    3. Apply to target — apply converted objects to the target database (live targets only)

    4. Back — return to actions menu"

    • Fix Action Items: Load action-items.md and follow the fixing workflow there.

    • Export as script: Run aws dms start-metadata-model-export-as-script --migration-project-identifier <migration_project_identifier> --origin TARGET --selection-rules '<json>'. Extract RequestIdentifier. Wait via aws dms wait metadata-model-exported-as-script --migration-project-identifier <id> --filter 'Name=schema-conversion-operation-id,Values=<RequestIdentifier>'. Provide the S3 link on completion.

    • Apply to target: Run aws dms start-metadata-model-export-to-target --migration-project-identifier <migration_project_identifier> --selection-rules '<json>'. Optionally pass --overwrite-extension-pack if the customer confirms. Extract RequestIdentifier. Wait via aws dms wait metadata-model-exported-to-target --migration-project-identifier <id> --filter 'Name=schema-conversion-operation-id,Values=<RequestIdentifier>'. Inform the customer on completion.

    • Back: Return to Actions Menu.

After completing, ask the customer what they'd like to do next.


Assess Database

Assessment analyzes conversion complexity and generates an conversion assessment report without actually converting any objects. Use this when the customer wants to understand the migration effort before committing to conversion.

Important: If the customer already ran a conversion on the same scope, a separate assessment is not necessary — conversion already produces an conversion assessment report. Inform the customer: "You already have an conversion assessment report from the conversion you ran. Would you like me to show that report instead, or do you want to re-run assessment on a different scope?"

  1. Ask what to assess: Ask the customer what they want to assess (e.g., "all schemas", "schema pg_catalog", "tables starting with PROD_").

  2. Build selection rules: Translate the customer's natural language to selection rules JSON. Refer to Selection rules in DMS Schema Conversion for format, wildcards, and vendor-specific locators.

  3. Run assessment: Call start-metadata-model-assessment with the migration project and selection rules. Extract RequestIdentifier from the response.

  4. Wait for completion: Wait using the DMS waiter:

    aws dms wait metadata-model-assessed \
      --migration-project-identifier <migration_project_identifier> \
      --filter 'Name=schema-conversion-operation-id,Values=<RequestIdentifier>'

    If the waiter fails or is unavailable, fall back to polling describe-metadata-model-assessments every 30 seconds with --filter Name=request-id,Values=<RequestIdentifier>. Terminal statuses: SUCCESS (proceed) or FAILED (check error).

  5. Export conversion assessment report: On success, call export-metadata-model-assessment with the same selection rules. Provide the customer with S3 links for both PDF and CSV reports (PdfReport.S3ObjectKey and CsvReport.S3ObjectKey). The report contains conversion complexity statistics, Action Items, and estimated effort.

  6. Show summary: Download the Summary CSV from S3 using aws s3 cp s3://<bucket>/<CsvReport.S3ObjectKey> ./Summary.csv. Present its contents to the customer — show the number of objects per category, how many converted automatically, and how many have Action Items at each complexity level.

  7. Offer to fix Action Items: Ask the customer:

    "Would you like me to help fix the Action Items?"

    If yes, load action-items.md and follow the fixing workflow there.

After completing, ask the customer what they'd like to do next.


Review Action Items

Load action-items.md and follow the workflow there.

After completing, ask the customer what they'd like to do next.


Work with Tree

The metadata tree represents database schemas hierarchically. It contains two kinds of elements:

  • Objects — actual database objects (tables, functions, views, sequences, indexes) that have SQL definitions

  • Categories — virtual grouping containers ("Schemas", "Tables", "Functions") that organize objects for navigation but have no SQL definitions

The tree uses on-demand loading — metadata is retrieved from the database only when imported. See Navigating the metadata model for full details.

Navigation uses two APIs:

  • describe-metadata-model-children — returns the children of a given node, each with its own SelectionRules for drilling deeper

  • describe-metadata-model — returns the name, type, and SQL definition of a specific object

Both require --origin SOURCE or --origin TARGET and accept only explicit selection rules.

  1. Show tree root: Call describe-metadata-model-children with selection rules targeting the root level and --origin SOURCE. If the tree is empty, automatically run a metadata import (same as Auto Import) and then re-display the tree root.

  2. Navigate: Each child in the response has MetadataModelName and SelectionRules. Present the children and ask the customer what to do:

    • Show children — drill into a child by calling describe-metadata-model-children with the child's SelectionRules as the --selection-rules parameter

    • Show definition — display the DDL for the selected object (see step 3). Only available for objects, not categories.

    • Go up — return to the parent node

    • Exit tree — return to actions menu

  3. Show definition: Call describe-metadata-model with the child's SelectionRules and --origin SOURCE. The response includes Definition (SOURCE DDL) and TargetMetadataModels (list of converted counterparts with their own SelectionRules). To get the TARGET DDL, call describe-metadata-model again with SelectionRules from TargetMetadataModels[0] and --origin TARGET. Present both clearly labeled as SOURCE and TARGET.

  4. Refresh from database: If the customer asks to refresh, run start-metadata-model-import with selection rules scoped to the current tree position, --origin SOURCE --refresh. Extract RequestIdentifier. Wait via aws dms wait metadata-model-imported --migration-project-identifier <id> --filter 'Name=schema-conversion-operation-id,Values=<RequestIdentifier>'. After refresh completes, re-display the current node's children.

After completing, ask the customer what they'd like to do next.


Convert Statement

Restriction: This feature is only available for SQL Server → PostgreSQL/Aurora PostgreSQL migration projects. Do NOT offer or show this option for any other source/target engine combination.

  1. Determine context: Navigate the metadata tree to find the target location. For SQL Server this is server → database → schema; for other engines it's server → schema. Use describe-metadata-model-children to drill into nodes until you reach the schema level. Let the customer pick the schema (or database + schema for SQL Server). If the tree is empty, ask the customer to provide the location manually.

  2. Get the SQL statement: Ask the customer for the SQL statement they want to convert.

  3. Build selection rules for the schema: Build selection rules targeting the schema location. See Selection rules in DMS Schema Conversion for format and vendor-specific locators.

  4. Create metadata model: Generate a unique model name (e.g., statement-<timestamp>). Call start-metadata-model-creation with:

    • --selection-rules — the schema selection rules from step 3

    • --metadata-model-name — the generated model name

    • --properties '{"StatementProperties": {"Definition": "<sql_statement>"}}'

    Extract RequestIdentifier from the response. Wait via aws dms wait metadata-model-created --migration-project-identifier <id> --filter 'Name=schema-conversion-operation-id,Values=<RequestIdentifier>'.

  5. Build selection rules for the statement: Build selection rules targeting the specific statement. See Selection rules in DMS Schema Conversion — use statement-name set to the model name.

  6. Convert the created model: Call start-metadata-model-conversion with the statement selection rules from step 5. Extract RequestIdentifier. Wait via aws dms wait metadata-model-converted --migration-project-identifier <id> --filter 'Name=schema-conversion-operation-id,Values=<RequestIdentifier>'.

  7. Show converted result: Call describe-metadata-model with the statement selection rules from step 5 and --origin SOURCE. From the response, extract TargetMetadataModels[0].SelectionRules. Then call describe-metadata-model with those target selection rules and --origin TARGET. Present the converted SQL from the Definition field clearly to the customer.

  8. Export conversion assessment report: Call export-metadata-model-assessment with the source selection rules from step 5. Provide the customer with S3 links for PDF and CSV reports.

After completing, ask the customer what they'd like to do next.


Database Statistics

When a customer asks about their source database statistics — such as the number of objects, object types, schema sizes, or a general overview — run an assessment and present the results as a concise summary.

  1. Build selection rules based on the customer's scope. If they specify particular schemas or objects, scope accordingly. If no scope is specified, default to all schemas on the source server (wildcard %). See Selection rules in DMS Schema Conversion for JSON format.

  2. Run assessment: Call start-metadata-model-assessment with the migration project and selection rules. See schema-conversion-operations.md for execution details.

  3. Wait for completion using the DMS waiter or fallback polling as described in schema-conversion-operations.md.

  4. Export conversion assessment report: Call export-metadata-model-assessment with the same selection rules.

  5. Download and present only what the customer asked for: Download the Summary CSV from S3:

    aws s3 cp s3://<bucket>/<CsvReport.S3ObjectKey> ./Summary.csv

    The report contains many data points. Present only the information the customer requested — do not dump the entire report. For example:

    • If they asked "how many tables?" → show only the table count

    • If they asked about a specific schema → show only that schema's stats

  6. Offer next steps: Ask if they'd like to see conversion complexity or proceed with conversion.

Constraints:

  • If the customer specifies a scope, use it. If not, default to all schemas.

  • Present only what the customer asked for — do not overwhelm with unrequested data.

  • Present statistics in a clear, tabular format.

After completing, ask the customer what they'd like to do next.


Clean Up

Delete the migration project and its associated DMS resources. Resources MUST be deleted in dependency order.

  1. Confirm with customer: List the resources that will be deleted and ask for confirmation:

    aws dms describe-migration-projects --filter Name=migration-project-identifier,Values=<migration_project_identifier>

    Show the project name, source/target data providers, and instance profile.

  2. Delete migration project:

    aws dms delete-migration-project \
      --migration-project-identifier <migration_project_identifier>
  3. Delete data providers: Delete both source and target data providers:

    aws dms delete-data-provider \
      --data-provider-identifier <source_data_provider_identifier>
    aws dms delete-data-provider \
      --data-provider-identifier <target_data_provider_identifier>
  4. Delete instance profile:

    aws dms delete-instance-profile \
      --instance-profile-identifier <instance_profile_identifier>
  5. Delete subnet group:

    aws dms delete-replication-subnet-group \
      --replication-subnet-group-identifier <subnet_group_identifier>
  6. Confirm completion: Inform the customer that all DMS Schema Conversion resources have been removed.

Constraints:

  • You MUST get explicit customer confirmation before deleting any resources.

  • You MUST delete in order: migration project first, then data providers, then instance profile, then subnet group — deleting in the wrong order will fail due to dependencies.

  • You MUST NOT delete the underlying infrastructure (VPC, subnets, security groups, RDS instances, Secrets Manager secrets) — those are outside the scope of DMS Schema Conversion cleanup.

After completing, ask the customer what they'd like to do next.


Cancel Awareness

During any running async operation, if the customer requests cancellation, refer to cancel-operations.md for the correct cancel command mapping.


Security Considerations

  • Credentials: All database credentials are stored in AWS Secrets Manager. Never embed credentials in data provider settings or log them to output.

  • Encryption at rest: S3 buckets use SSE-S3 encryption (default). SSE-KMS is not supported by DMS Schema Conversion.

  • Encryption in transit: Online connections should use require or stronger SSL mode. none should only be used in isolated test environments.

  • IAM least-privilege: All IAM roles use confused-deputy condition keys (aws:SourceAccount, aws:SourceArn) and scoped resource ARNs.

  • Network access: DMS instance profiles operate within VPC subnets with security group restrictions.

  • See DMS security best practices for additional guidance.


Error Handling

When any operation fails or returns an error, load troubleshooting.md and follow its guidance to diagnose and resolve the issue. Explain the error to the customer in plain language and offer options: retry, try a different action, or exit.

Files

references/setup-wizard.md

DMS Schema Conversion: Setup Wizard Reference

Table of Contents

  • Global Constraints

  • Phase 1 — Project Name

  • Phase 2 — Target Type Selection

  • Phase 3 — Source Database

    • 3d — Offline source configuration

  • Phase 4 — Network Investigation & Connectivity

  • Phase 5 — Create DMS Subnet Group

  • Phase 6 — Database Credentials

  • Phase 7 — Create Data Providers

  • Phase 8 — S3 Bucket

  • Phase 9 — IAM Roles

  • Phase 10 — Create Instance Profile

  • Phase 11 — Transformation Rules (Optional)

  • Phase 12 — Create Migration Project & Summary


Global Constraints

Execute commands using available tools from the AWS MCP server when connected — it provides sandboxed execution, audit logging, and observability. When the MCP server is not available, fall back to the AWS CLI or shell as needed.

  • You MUST resolve aws_account_id by running aws sts get-caller-identity and extracting the Account field

  • You MUST present one phase at a time — do NOT ask for all parameters at once

  • You MUST confirm each resource was created successfully before moving to the next phase

  • You MUST show a running summary of collected values at the start of each new phase

  • You MUST handle ResourceAlreadyExistsFault and similar errors by reusing the existing resource

  • You MUST NOT display or log passwords at any point

  • You SHOULD suggest sensible defaults based on already-collected information


Phase 1 — Project Name

Goal: Establish a project name prefix used for all resource names.

Ask:

"What would you like to name this migration project? This will be used as a prefix for all created resources (e.g., myproject → myproject-instance-profile, myproject-s3-bucket, etc.)."

Resource Naming Convention — you MUST use these exact names (no variations):

ResourceName pattern
Migration Project<project_name>-migration-project
Instance Profile<project_name>-instance-profile
DMS Subnet Group<project_name>-subnet-group
Source Data Provider<project_name>-source
Target Data Provider<project_name>-target
S3 Bucket (migration artifacts)<project_name>-sc-bucket-<aws_account_id>-<aws_region>
Secrets IAM Role<project_name>-sc-secrets-role
S3 IAM Role (migration artifacts)<project_name>-sc-s3-role
S3 Access Role (offline source, if applicable)<project_name>-sc-s3-access-role

Constraints:

  • Resolve aws_account_id by running aws sts get-caller-identity and extracting the Account field

  • Ask the customer which AWS region to use. Do NOT attempt to infer it from the STS response. Store as aws_region.

  • If region resolution fails, ask the customer to provide it manually

  • The project name MUST be between 1 and 25 characters, start with a lowercase letter or number, and contain only lowercase letters, numbers, and hyphens. Validate this before proceeding. If the customer provides uppercase characters, auto-lowercase the name and inform them. (The 25-character limit ensures the derived S3 bucket name <project_name>-sc-bucket-<account_id>-<region> stays within the 63-character S3 bucket name limit even for the longest AWS region names.)

  • After the customer provides a name, you MUST check for existing resources that would be created under that prefix. Run all of the following lookups and present a consolidated summary before proceeding:

    
    aws dms describe-migration-projects --filters Name=migration-project-identifier,Values=<project_name>-migration-project
    aws dms describe-instance-profiles --filters Name=instance-profile-identifier,Values=<project_name>-instance-profile
    aws dms describe-replication-subnet-groups --filters Name=replication-subnet-group-id,Values=<project_name>-subnet-group
    aws dms describe-data-providers --filters Name=data-provider-identifier,Values=<project_name>-source
    aws dms describe-data-providers --filters Name=data-provider-identifier,Values=<project_name>-target
    aws s3api head-bucket --bucket <project_name>-sc-bucket-<aws_account_id>-<aws_region>
    aws iam get-role --role-name <project_name>-sc-secrets-role
    aws iam get-role --role-name <project_name>-sc-s3-role
    aws iam get-role --role-name <project_name>-sc-s3-access-role
    aws iam get-role --role-name dms-vpc-role
    aws iam get-role --role-name dms-cloudwatch-logs-role
    
  • For each lookup, treat NotFoundException, ResourceNotFoundException, NoSuchEntity, or 404 as "not found" — do NOT surface these as errors to the customer

  • After all lookups complete, present a table of what already exists vs. what will be created:

    ResourceStatus
    Migration Project <project_name>-migration-projectEXISTS / will be created
    Instance Profile <project_name>-instance-profileEXISTS / will be created
    Subnet Group <project_name>-subnet-groupEXISTS / will be created
    Source Data Provider <project_name>-sourceEXISTS / will be created
    Target Data Provider <project_name>-targetEXISTS / will be created
    S3 Bucket <project_name>-sc-bucket-<aws_account_id>-<aws_region>EXISTS / will be created
    Secrets IAM Role <project_name>-sc-secrets-roleEXISTS / will be created
    S3 IAM Role <project_name>-sc-s3-roleEXISTS / will be created
    S3 Access Role <project_name>-sc-s3-access-role (offline source)EXISTS / will be created if needed
    DMS VPC Role dms-vpc-roleEXISTS / will be created
    DMS CloudWatch Role dms-cloudwatch-logs-roleEXISTS / will be created
  • If the migration project already exists, inform the customer and ask: "A migration project with this name already exists. Would you like to (1) choose a different name, or (2) continue anyway and reuse existing resources where possible? If you choose option 2, please provide a new name for any resources that need to be recreated."

  • You MUST wait for the customer's confirmation before proceeding to Phase 2


Phase 2 — Target Type Selection

Goal: Determine whether the target is a live database instance or a virtual target.

Explain:

"DMS Schema Conversion supports two target modes:

  • Live database — connects to a live Amazon RDS, Aurora, or Redshift instance. DMS reads its network config automatically.

  • Virtual — no live target database needed. Useful for reviewing converted schema without an actual DB.

Which would you like? (live / virtual)"

Supported target engines: aurora-postgresql, postgres, mysql, aurora, redshift, db2. See DMS SC supported target databases for the full list. A value of aurora represents Amazon Aurora MySQL-Compatible Edition.

Constraints:

  • Accept live or virtual (case-insensitive); store as use_virtual_target

  • If live: Ask for the target engine type (e.g., aurora-postgresql, mysql, redshift). Then ask:

    "Is your target an Amazon RDS/Aurora instance or Redshift cluster? If yes, provide the ARN and I'll retrieve connection details automatically. Otherwise, provide hostname, port, database name."

    • If ARN provided: Call aws rds describe-db-instances (or describe-db-clusters for Aurora, or aws redshift describe-clusters for Redshift) to fetch target_hostname, target_port, and target_database_name. Also extract target_vpc_id, target_subnet_ids, and target_security_group_ids from the instance/cluster metadata. Inform the customer of what was found.

    • If no ARN: Ask for the target database connection info (hostname, port, database name). Also ask for the VPC ID, subnet IDs, and security group IDs associated with the target.

    Store as target_engine, target_hostname, target_port, target_database_name, target_vpc_id, target_subnet_ids, target_security_group_ids.

  • If virtual: Ask for the target engine type (e.g., aurora-postgresql, mysql, redshift). Store as target_engine.

    Prepare the target data provider params for use in Phase 7b:

    
    target_data_provider_params = {
        "DataProviderName": "<project_name>-target",
        "Engine": "<target_engine>",
        "Virtual": True,
        "Settings": {
            "<TargetEngineSettings>": {
                "ServerName": "virtual",
                "Port": <default_port>,
                "DatabaseName": "virtual",
                "SslMode": "none"
            }
        }
    }
    

    Map target_engine → Settings key and default port:

    • aurora-postgresql or postgres → PostgreSqlSettings, port 5432

    • mysql or aurora → MySqlSettings, port 3306

    • redshift → RedshiftSettings, port 5439

    • db2 → IbmDb2LuwSettings, port 50000


Phase 3 — Source Database

Goal: Collect source engine and connection details.

3a — Source type

Ask for source engine. Supported source engines: sqlserver, oracle, mysql, postgres, db2, db2-zos, sybase. See DMS SC supported source databases for the full list. The customer may provide the engine name in any format — map it to the correct API identifier automatically.

3b — Source mode (online / offline)

If source engine is sqlserver, ask:

"Would you like to connect directly to the source database (online mode), or use exported DDL scripts from S3 (offline mode)?

  • Online — DMS connects to your database to read metadata directly.

  • Offline — DMS reads metadata from DDL scripts you've uploaded to S3. No database connectivity required."

Store as source_mode (online or offline).

If offline: Proceed to Phase 3d — Offline Source Configuration.

If source engine is NOT sqlserver, set source_mode = online (offline is available only for SQL Server).

3c — Source connection (online mode only)

Skip this step if source_mode = offline.

Ask for hostname, port, and database name in a single prompt. If the source is an RDS instance, offer to look up the connection details automatically:

"Is your source database an RDS instance? If yes, provide the RDS instance ARN or identifier and I'll retrieve the connection details automatically. Otherwise, please provide the hostname, port, and database name."

  • If RDS source: Call aws rds describe-db-instances (or describe-db-clusters for Aurora) to fetch source_hostname, source_port, and source_database_name. Inform the customer of what was found.

  • If not RDS: Ask for hostname, port, and database name directly.

Store as source_hostname, source_port, source_database_name.

3d — Offline source configuration

Skip this step if source_mode = online.

Step 1 — DDL Scripts (Offline Source)

Ask:

"What is the current state of your DDL scripts?

  1. Already exported and uploaded to S3

  2. Already exported but not yet uploaded to S3

  3. Not yet exported — I'd like help"

Option 1 (exported + uploaded): Proceed to Step 2.

Option 2 (exported, not uploaded):

Ensure the DDL scripts end up as individual .sql files in S3. If the customer provides an archive (.zip, .tar.gz, .tar), extract it first. Adapt to whatever the customer provides:

  • Agent has filesystem access to the files: Extract if archive, then upload .sql files to S3 with --sse AES256.

  • Agent does NOT have filesystem access (remote): Provide the customer with a simple command. For a folder of .sql files: aws s3 sync ./ s3://<bucket>/<prefix>/ --sse AES256. For an archive: ask the customer to upload it to S3 with aws s3 cp, then the agent downloads, extracts, and re-uploads the .sql files to the correct prefix.

Constraints:

  • Do NOT generate presigned URLs as the default upload method — prefer aws s3 sync or aws s3 cp.

  • Do NOT ask the customer about encryption for files the agent uploads — always use --sse AES256.

  • Do NOT ask for the database name during upload — derive it from DDL content after upload (see Step 3). Use any reasonable prefix for the initial upload (e.g., ddl/ or the project name).

Verify upload: aws s3 ls s3://<bucket>/<prefix>/ --recursive | head -10. Proceed to Step 2.

Option 3 (not exported):

Provide the customer with a template export script. Do NOT ask for database credentials — always present the script with placeholder variables for the customer to fill in.

Read Export SQL Server database objects and generate a PowerShell SMO script with clearly marked placeholders (hostname, database name, output directory, username, password). Let the customer run it independently.

Alternatively, provide the documentation link and DDL structure requirements (below) for customers who prefer their own tooling.

If the customer provides a file path or mentions having files at any point, switch to Option 2 flow immediately.

DDL structure requirements (inform customer if they export themselves):

  • One SQL file per database object

  • Each file contains exactly one CREATE statement

  • USE [DatabaseName]; at the top of each file

  • All objects for one database under a single S3 prefix

  • No DML or DROP statements

Step 2 — S3 Configuration (Offline Source)
  1. S3 path: Ask:

    "Please provide the S3 path to your DDL scripts (e.g., s3://my-bucket/MyDatabase/)."

    Store as ddl_s3_path.

  2. Verify S3 content and region: List objects to confirm scripts are present:

    
    aws s3 ls <ddl_s3_path> --recursive | head -10
    

    If empty or path not found, inform the customer and ask to correct.

    Also verify the bucket is in the same region as the DMS resources:

    
    aws s3api get-bucket-location --bucket <bucket_name>
    

    A null or empty LocationConstraint means the bucket is in us-east-1. If the bucket region does not match aws_region, warn the customer: "Your DDL scripts bucket is in a different region than your DMS resources. DMS requires the S3 bucket to be in the same region. Please provide a bucket in <aws_region> or copy the scripts to a bucket in that region."

  3. S3 access role: Ask:

    "Do you have an IAM role that grants DMS read access to this S3 bucket? If yes, provide the ARN. If no, I'll create one."

    • If provided: Validate with aws iam get-role. Store as offline_s3_access_role_arn.

    • If not provided: Create the role in Phase 9e.

  4. KMS encryption (optional): Skip this step if the agent uploaded the files (the agent already used SSE-S3 / --sse AES256 which is the recommended default for DMS Schema Conversion).

    Only ask if the customer provided a pre-existing S3 path (Option 1):

    "Are the S3 objects encrypted with a customer-managed KMS key? (yes / no)"

    • If yes: Ask for the KMS key ARN. Store as s3_kms_key_arn. The S3 access role will need kms:Decrypt permission on this key (handled in Phase 9e).

    • If no: No additional configuration needed (SSE-S3 is the default and requires no extra permissions).

    Constraint: Do NOT ask about encryption if you already uploaded the files yourself — you know the answer.

Step 3 — Prepare Source Data Provider Settings (Offline Source)

Derive DatabaseName from DDL content:

The DatabaseName field MUST match the database name used in the DDL scripts. DMS uses it to construct the metadata tree and match USE [DatabaseName] statements. An incorrect value causes import to fail with "Unexpected application error".

To derive the correct value:

  1. Download one .sql file from the S3 path (preferably _create_database.sql or any file with a USE statement):

    
    aws s3 cp <ddl_s3_path><first_file> - | head -5
    
  2. Look for USE [<name>] or CREATE DATABASE [<name>] — extract <name> as the database name. Do not log or persist this output.

  3. If no USE/CREATE DATABASE statement is found, use the last path segment of ddl_s3_path (the folder name containing the DDL scripts) as the database name.

  4. If the DDL scripts are at the bucket root (no prefix folder), ask the customer for the database name.

Store the derived value as <database_name>.


source_engine = "sqlserver"
source_mode = "offline"
source_data_provider_params = {
    "DataProviderName": "<project_name>-source",
    "Engine": "sqlserver",
    "Virtual": True,
    "Settings": {
        "MicrosoftSqlServerSettings": {
            "ServerName": "offline",
            "Port": 1433,
            "DatabaseName": "<database_name>",
            "SslMode": "none",
            "S3Path": "<ddl_s3_path>",
            "S3AccessRoleArn": "<offline_s3_access_role_arn>"
        }
    }
}

Use source_data_provider_params directly as the params argument when calling CreateDataProvider in Phase 7a.

Constraint: Do NOT hardcode "DatabaseName": "offline". Do NOT ask the customer for the database name if it can be derived from the DDL scripts or S3 path.


Phase 4 — Network Investigation & Connectivity

Goal: Determine VPC, subnets, and security groups for the DMS instance profile.

4a — Derive or ask for VPC

Skip Phase 4 entirely (4a, 4b, 4c) if source_mode = offline AND use_virtual_target = true. No network configuration is needed — the instance profile will be created without subnet group or security groups.

  • If live target: Use target_vpc_id from Phase 2. Ask if the customer also wants to reuse the target subnets and security groups. If yes, skip to 4c.

    Note: Reusing the same security group is less secure than creating a dedicated SG with minimal permissions.

  • If virtual target AND source_mode = online: Use the VPC where the source database resides. If the source is an RDS instance, derive the VPC from the RDS metadata. Otherwise, ask the customer which VPC the source database is in.

4b — Collect subnets and security groups manually
  • Ask for at least two subnet IDs from different AZs (comma-separated)

  • Validate with: aws ec2 describe-subnets --subnet-ids <ids> --query Subnets[*].{ID:SubnetId,AZ:AvailabilityZone,VPC:VpcId}

  • Verify all subnets belong to the same VPC and span at least 2 AZs

  • Ask for security group IDs (comma-separated)

  • After collecting security group IDs, run aws ec2 describe-security-groups --group-ids <ids> and check for rules referencing 0.0.0.0/0 or ::/0. If found, warn the customer and recommend scoping rules to the specific database port and source CIDR or security group reference.

4c — Connectivity confirmation

Skip this step if source_mode = offline — no source database connectivity is needed.

Ask:

"Does your source database require special network setup to be reachable from this VPC? (VPN, Direct Connect, VPC peering, firewall rules) (yes / no)"

Store final vpc_id, subnet_ids, security_group_ids.


Phase 5 — Create DMS Subnet Group

Skip this phase if source_mode = offline AND use_virtual_target = true.

Goal: Create the subnet group for the DMS instance profile.


aws dms create-replication-subnet-group \
  --replication-subnet-group-identifier <project_name>-subnet-group \
  --replication-subnet-group-description "Subnet group for <project_name>" \
  --subnet-ids <subnet_ids>

Store subnet_group_identifier. On ResourceAlreadyExistsFault, reuse existing.


Phase 6 — Database Credentials

Goal: Collect the Secrets Manager secrets for both source and target database credentials.

6a — Source credentials

Ask if the customer needs help setting up source database credentials. Guide the customer based on source data provider prerequisites for required permissions.

Ask for the Secrets Manager secret ARN containing the source database credentials:

"Please provide the ARN of the Secrets Manager secret with your source database username and password. If your source is an RDS instance, you can find the secret in the RDS console under 'Connectivity & security'."

Important: The secret must contain a JSON with keys username and password. Warn the customer that the RDS-managed admin secret has extensive privileges that Schema Conversion does not need. Recommend creating a dedicated database user with minimal required permissions. See required permissions for the full list.

Store as source_secret_arn.

6b — Target credentials

Ask if the customer needs help setting up target database credentials. Guide the customer based on target data provider prerequisites for required permissions.

If virtual target: A secret is still required by DMS even though it won't be used for an actual connection. Create a placeholder secret automatically (the password is non-sensitive — used only to satisfy the API schema requirement):


aws secretsmanager create-secret \
  --name <project_name>-target-dummy-secret \
  --secret-string '{"username":"virtual_placeholder","password":"'"$(openssl rand -base64 16)"'"}'

On ResourceExistsException, reuse the existing secret. Store the ARN as target_secret_arn.

If live target (RDS/Aurora/Redshift): If the customer provided an ARN in Phase 2, automatically retrieve the associated secret ARN from the instance/cluster metadata (e.g., MasterUserSecret.SecretArn from describe-db-instances or describe-db-clusters). Inform the customer of the secret found. If no secret is associated with the instance, fall back to asking manually.

If live target (other or manual): Ask:

"Please provide the ARN of the Secrets Manager secret with your target database username and password."

Important: Warn the customer that managed admin secrets have extensive privileges that Schema Conversion does not need. Recommend creating a dedicated database user with minimal required permissions and storing those credentials in a separate secret.

Store as target_secret_arn.


Phase 7 — Create Data Providers

Goal: Register source and target data providers in DMS.

7a — Source data provider

If source_mode = offline:

aws dms create-data-provider \
  --data-provider-name <project_name>-source \
  --engine sqlserver \
  --virtual \
  --settings '{"MicrosoftSqlServerSettings":{"ServerName":"offline","Port":1433,"DatabaseName":"<database_name>","SslMode":"none","S3Path":"<ddl_s3_path>","S3AccessRoleArn":"<offline_s3_access_role_arn>"}}'

If source_mode = online:

aws dms create-data-provider \
  --data-provider-name <project_name>-source \
  --engine <source_engine> \
  --settings '{"<EngineSettings>":{"ServerName":"<source_hostname>","Port":<source_port>,"DatabaseName":"<source_database_name>","SslMode":"<ssl_mode>"}}'

Store source_data_provider_arn. Do NOT include credentials in settings.

SSL/TLS: For offline mode, SslMode is already set to "none" — do NOT ask the customer. For online mode, ask the customer which SSL mode to use (require, verify-ca, verify-full, none). Recommend require or higher. Warning: none transmits credentials and data unencrypted — use only in isolated test environments with no sensitive data.

7b — Target data provider

If virtual target:

aws dms create-data-provider \
  --data-provider-name <project_name>-target \
  --engine <target_engine> \
  --virtual \
  --settings '{"<TargetEngineSettings>":{"ServerName":"virtual","Port":<default_port>,"DatabaseName":"virtual","SslMode":"none"}}'

Use the same engine → Settings key mapping from Phase 2 (PostgreSqlSettings/5432, MySqlSettings/3306, RedshiftSettings/5439, IbmDb2LuwSettings/50000).

If live target:

aws dms create-data-provider \
  --data-provider-name <project_name>-target \
  --engine <target_engine> \
  --settings '{"<EngineSettings>":{"ServerName":"<target_hostname>","Port":<target_port>,"DatabaseName":"<target_database_name>","SslMode":"<ssl_mode>"}}'

Do NOT pass Virtual for live targets.

Store target_data_provider_arn.

7c — Verify Virtual flag

You MUST verify both data providers have the correct Virtual flag immediately after creation.

Expected values:

  • Source: Virtual = True if source_mode = offline, False if online

  • Target: Virtual = True if use_virtual_target = true, False if live target

For each data provider, describe and check the Virtual field:

aws dms describe-data-providers \
  --filters Name=data-provider-identifier,Values=<project_name>-source

If the Virtual flag does not match the expected value, attempt to modify:

aws dms modify-data-provider \
  --data-provider-identifier <project_name>-source \
  --engine <engine> \
  --virtual \
  --settings '<settings_json_from_describe>'

If modify fails ("Cannot convert a non-virtual data provider to virtual"), delete and recreate with the correct flag:

aws dms delete-data-provider \
  --data-provider-identifier <project_name>-source

aws dms create-data-provider \
  --data-provider-name <project_name>-source \
  --engine <engine> \
  --virtual \
  --settings '<settings_json>'

Repeat for the target data provider. After any recreate, re-store the new ARN from the create-data-provider response — the old ARN is no longer valid. Do NOT proceed to Phase 8 until both data providers have the correct Virtual flag.


Phase 8 — S3 Bucket

Goal: Ensure an S3 bucket exists for migration artifacts.

Ask if the customer has an existing bucket. If yes, validate with aws s3api head-bucket. If no, create <project_name>-sc-bucket-<aws_account_id>-<aws_region>.


# For us-east-1:
aws s3api create-bucket --bucket <bucket_name> --region us-east-1

# For all other regions:
aws s3api create-bucket \
  --bucket <bucket_name> \
  --region <aws_region> \
  --create-bucket-configuration LocationConstraint=<aws_region>

aws s3api put-bucket-versioning \
  --bucket <bucket_name> \
  --versioning-configuration Status=Enabled

aws s3api put-public-access-block \
  --bucket <bucket_name> \
  --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

aws s3api put-bucket-policy --bucket <bucket_name> --policy '{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DenyInsecureTransport",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": ["arn:aws:s3:::<bucket_name>", "arn:aws:s3:::<bucket_name>/*"],
    "Condition": {"Bool": {"aws:SecureTransport": "false"}}
  }]
}'

Constraints:

  • The bucket name MUST include the region suffix: <project_name>-sc-bucket-<aws_account_id>-<aws_region>

  • Do NOT configure SSE-KMS — DMS Schema Conversion only supports SSE-S3 (default)

  • Store bucket_name


Phase 9 — IAM Roles

Goal: Create IAM roles: Secrets Manager access role, S3 access role, DMS VPC role, and DMS CloudWatch Logs role.

Important — two distinct S3 roles exist. Do NOT confuse them when troubleshooting:

RoleName patternPurposePermissions
S3 Role (9b)<project_name>-sc-s3-roleDMS reads/writes migration artifacts (reports, converted DDL, tree data) to the artifacts buckets3:GetObject, s3:GetObjectVersion, s3:PutObject + bucket-level s3:ListBucket, s3:GetBucketLocation, s3:GetBucketVersioning on the artifacts bucket
S3 Access Role (9e)<project_name>-sc-s3-access-roleDMS reads DDL scripts from the offline source buckets3:GetObject, s3:ListBucket on the DDL scripts bucket

When an S3 permission error occurs during import, the problem is almost always the S3 Access Role (9e) — not the S3 Role (9b). When an S3 error occurs during project creation or export, the problem is the S3 Role (9b).

9a — Secrets Manager Role

Ask if an existing role is available. If yes, validate with aws iam get-role. If no, create:

  1. Create the role with trust policy (includes condition keys to prevent confused deputy):

    
    aws iam create-role \
      --role-name <project_name>-sc-secrets-role \
      --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"dms.amazonaws.com"},"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":"<aws_account_id>"},"ArnLike":{"aws:SourceArn":"arn:aws:dms:<aws_region>:<aws_account_id>:*"}}}]}'
    
  2. Attach a policy granting access to the secret ARNs used by the migration project. See IAM policies for DMS for the required permissions (Secrets Manager and KMS actions). Scope the resource to <source_secret_arn> and <target_secret_arn>.

Store secrets_role_arn.

9b — S3 Role

Ask if an existing role is available. If yes, validate. If no, create:

  1. Create the role with trust policy (includes condition keys to prevent confused deputy):

    
    aws iam create-role \
      --role-name <project_name>-sc-s3-role \
      --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"dms.amazonaws.com"},"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":"<aws_account_id>"},"ArnLike":{"aws:SourceArn":"arn:aws:dms:<aws_region>:<aws_account_id>:*"}}}]}'
    
  2. Attach a policy granting S3 access to the artifacts bucket. Follow the exact policy from IAM policies for DMS SC: two statements — bucket-level (s3:ListBucket, s3:GetBucketLocation, s3:GetBucketVersioning on arn:aws:s3:::<bucket_name>) and object-level (s3:PutObject, s3:GetObject, s3:GetObjectVersion on arn:aws:s3:::<bucket_name>/*). Add aws:ResourceAccount condition for least-privilege.

Store s3_role_arn.

9c — DMS VPC Role

Required by DMS to manage VPC and ENI resources. The role name MUST be exactly dms-vpc-role — DMS looks it up by this fixed name. See IAM roles for DMS for details.

First check if the role exists:


aws iam get-role --role-name dms-vpc-role

If the role already exists (found in Phase 1 lookup or via the check above), skip creation. Otherwise create it:

  1. Create the role with trust policy for dms.amazonaws.com (includes condition keys to prevent confused deputy):

    
    aws iam create-role \
      --role-name dms-vpc-role \
      --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"dms.amazonaws.com"},"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":"<aws_account_id>"},"ArnLike":{"aws:SourceArn":"arn:aws:dms:<aws_region>:<aws_account_id>:*"}}}]}'
    
  2. Attach the AWS managed policy:

    
    aws iam attach-role-policy \
      --role-name dms-vpc-role \
      --policy-arn arn:aws:iam::aws:policy/service-role/AmazonDMSVPCManagementRole
    
9d — DMS CloudWatch Logs Role

Required by DMS to publish schema conversion logs to CloudWatch. The role name MUST be exactly dms-cloudwatch-logs-role. See IAM roles for DMS for details.

First check if the role exists:


aws iam get-role --role-name dms-cloudwatch-logs-role

If the role already exists (found in Phase 1 lookup or via the check above), skip creation. Otherwise create it:

  1. Create the role with trust policy for dms.amazonaws.com (includes condition keys to prevent confused deputy):

    
    aws iam create-role \
      --role-name dms-cloudwatch-logs-role \
      --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"dms.amazonaws.com"},"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":"<aws_account_id>"},"ArnLike":{"aws:SourceArn":"arn:aws:dms:<aws_region>:<aws_account_id>:*"}}}]}'
    
  2. Attach the AWS managed policy:

    
    aws iam attach-role-policy \
      --role-name dms-cloudwatch-logs-role \
      --policy-arn arn:aws:iam::aws:policy/service-role/AmazonDMSCloudWatchLogsRole
    
9e — S3 Access Role for Offline Source

Skip this step if source_mode = online or the customer already provided offline_s3_access_role_arn in Phase 3d.

Create an IAM role allowing DMS to read DDL scripts from the customer's S3 bucket (the bucket from ddl_s3_path, NOT the migration artifacts bucket from Phase 8):

  1. Create the role with trust policy:

    
    aws iam create-role \
      --role-name <project_name>-sc-s3-access-role \
      --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"dms.amazonaws.com"},"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":"<aws_account_id>"},"ArnLike":{"aws:SourceArn":"arn:aws:dms:<aws_region>:<aws_account_id>:*"}}}]}'
    
  2. Attach S3 read policy scoped to the DDL scripts bucket (extract bucket name from ddl_s3_path):

    
    aws iam put-role-policy \
      --role-name <project_name>-sc-s3-access-role \
      --policy-name S3ReadAccess \
      --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:ListBucket","Resource":"arn:aws:s3:::<ddl_bucket_name>"},{"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::<ddl_bucket_name>/*"}]}'
    
  3. If s3_kms_key_arn is set, add KMS decrypt:

    
    aws iam put-role-policy \
      --role-name <project_name>-sc-s3-access-role \
      --policy-name KmsDecrypt \
      --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"kms:Decrypt","Resource":"<s3_kms_key_arn>","Condition":{"StringEquals":{"kms:ViaService":"s3.<aws_region>.amazonaws.com"}}}]}'
    

Store offline_s3_access_role_arn.


Phase 10 — Create Instance Profile

Goal: Create the DMS instance profile that ties together the subnet group and security groups.

If source_mode = offline AND use_virtual_target = true:


aws dms create-instance-profile \
  --instance-profile-name <project_name>-instance-profile

Otherwise:


aws dms create-instance-profile \
  --instance-profile-name <project_name>-instance-profile \
  --subnet-group-identifier <subnet_group_identifier> \
  --vpc-security-groups <security_group_ids>

Store instance_profile_arn and instance_profile_name.


Phase 11 — Transformation Rules (Optional)

You MUST ask the customer about transformation rules before proceeding to Phase 12:

"Would you like to apply any transformation rules during conversion — such as renaming schemas, converting object names to uppercase/lowercase, or adding prefixes/suffixes? (yes / no)"

If yes, help them build the rules JSON. See Transformation rules in DMS Schema Conversion for format and options. Store as transformation_rules. If no, set to null.


Phase 12 — Create Migration Project & Summary

12a — Create Migration Project

Build source descriptor (always includes secret):

  • {"DataProviderIdentifier": "<source_data_provider_arn>", "SecretsManagerSecretId": "<source_secret_arn>", "SecretsManagerAccessRoleArn": "<secrets_role_arn>"}

Build target descriptor (always includes secret):

  • {"DataProviderIdentifier": "<target_data_provider_arn>", "SecretsManagerSecretId": "<target_secret_arn>", "SecretsManagerAccessRoleArn": "<secrets_role_arn>"}


aws dms create-migration-project \
  --migration-project-name <project_name>-migration-project \
  --instance-profile-identifier <instance_profile_name> \
  --schema-conversion-application-attributes '{"S3BucketPath":"s3://<bucket_name>","S3BucketRoleArn":"<s3_role_arn>"}' \
  --source-data-provider-descriptors '[{"DataProviderIdentifier":"<source_data_provider_arn>","SecretsManagerSecretId":"<source_secret_arn>","SecretsManagerAccessRoleArn":"<secrets_role_arn>"}]' \
  --target-data-provider-descriptors '[{"DataProviderIdentifier":"<target_data_provider_arn>","SecretsManagerSecretId":"<target_secret_arn>","SecretsManagerAccessRoleArn":"<secrets_role_arn>"}]'
  [--transformation-rules '<json>' if not null]

Store migration_project_arn and migration_project_name.

12b — Verify

If create-migration-project returns an error, surface the error message to the customer and refer to troubleshooting.md for diagnosis. Common sync errors include AccessDeniedFault (IAM permissions), ResourceNotFoundFault (instance profile or data provider not found), and InvalidResourceStateFault.

12c — Summary Table
ResourceNameARN / ID
DMS Subnet Group<project_name>-subnet-groupidentifier
Instance Profile<project_name>-instance-profileARN
Source Data Provider<project_name>-sourceARN
Target Data Provider<project_name>-targetARN
Source Secretcustomer-providedARN
Target Secretcustomer-providedARN
S3 Bucket<bucket_name>bucket name
Secrets IAM Role<project_name>-sc-secrets-role or existingARN
S3 IAM Role<project_name>-sc-s3-role or existingARN
Migration Project<project_name>-migration-projectARN

Then inform the customer:

"Setup complete."

Requirements and compatibility

Written for: Claude Code

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Names Claude Code tools, Needs an MCP server, Needs a command-line tool, Needs Node.js

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
AWS
Publisher
AWS (Official)
Source
aws/agent-toolkit-for-aws · skills/specialized-skills/migration-and-modernization-skills/dms-schema-conversion · commit 0a218f8
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • NOTICE (added by AutoGineer from NOTICE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by AWS or AWS.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download dms-schema-conversion.zip