The DRS Configuration Synchronizer (synchronizer) is an AWS Lambda function that runs periodically to ensure that each DRS source server's configuration settings conform to the desired state defined in source control. The synchronizer applies settings based on a set of defaults and optionally applies overrides to certain servers based on the AWS tags.
The synchronizer can be deployed in either a single account or multi-account DRS deployment. The synchronizer assumes a role in each AWS account where the DRS service is configured to perform synchronization.
- SAM CLI: The SAM CLI is used to build and deploy the syncrhonizer lambda function. Install the SAM CLI following the instructions in the documentation.
- Python 3: The deployment script is written in Python and automates the deployment of cloudformation stacks and AWS resource lookups. With Python3 installed, install the required Python packages in requirements.txt with the command:
python3 -m pip install -r requirements.txt --user
The deploy.py script referenced in the instructions will automate the deployment of CloudFormation stacks for the synchronizer solution.
The following CloudFormation stacks are created:
-
Stack Name: drs-configuration-synchronizer-lambda
- Resources:
- AWS Lambda function: This lambda function performs the configuration synchronization and is the heart of the solution.
- Resources:
-
Stack Name: drs-configuration-synchronizer-s3
- Resources:
- S3 Bucket: This S3 bucket is used for storing and managing deployment packages during lambda deployment. It also is used to store the execution reports for the synchronizer.
- Resources:
-
Stack Name: drs-configuration-synchronizer-sns-notifications
- Resources:
- SNS Topic: This SNS topic is used for sending notifications on synchronizer execution and results.
- Resources:
-
Stack Name: drs-configuration-synchronizer-account-role
- Resources:
- IAM Role: This role is assumed by the synchronizer lambda function in each DRS account in order to read and update DRS related configuration resources such as launch templates, DRS launch, and DRS replication configurations.
- Resources:
The following parameter options are supported:
--solution-account <AWS Account ID>
: REQUIRED - The AWS Account ID where the drs-configuration-synchronizer is deployed.--prefix <prefix name>
: The prefix to preprend in front of each stack name, eg prefixmyco
results in stack namemyco-drs-configuration-synchronizer-lambda
.--environment <environment name>
: The environment name to append to the end of each stack name, eg environmentdev
results in stack namedrs-configuration-synchronizer-dev
.--account-role-only
: Deploy only the IAM role assumed by the synchronizer. You need to deploy account roles to each DRS account you want the synchronizer to update in addition to deploying the solution.--cleanup
: Cleanup the deployed stacks and AWS resources. If you deployed with the --prefix or --environment option, then you must cleanup with the same option parameters--prompt
: Whether to prompt and require you to press enter after each stack is deployed.
In a single account architecture, you deploy the synchronizer to the AWS account and region where DRS is configured.
- Rename the default directory under the configuration subdirectory with the same name as your AWS account id (ex: 012345678901)
- Update the defaults and overrides for launch configuration settings, launch template settings, and replication configuration settings to meet your requirements within the directory.
- Set the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN AWS environment variables with the appropriate credentials. You will also need to set the environment variable AWS_DEFAULT_REGION to the region you are deploying to.
- Run the provided python deployment script deploy.py with your preferred options:
python3 deploy.py --solution-account <Your AWS account ID where you are deploying the solution>
In a multi-account architecture, the synchronizer will assume a role in each configured DRS account.
- Complete the single account deployment steps for the AWS account where you want the solution to operate.
- Copy the single-account subdirectory under the
configuration
subdirectory for each additional AWS account you want to synchronize configurations. - Update the files within each AWS account subdirectory as needed.
- For each additional AWS account the synchronizer should operate on, deploy the IAM role that the synchronizer will assume with the following command:
python3 deploy.py --account-role-only --solution-account <Your AWS account ID where you are deploying the solution>
NOTE: Make sure you update the AWS environment variables with the credentials before deploying to each account.
The synchronizer function is periodically triggered by Rule defined in the AWS EventBridge service. The EventBridge rule defines the schedule using a cron expression. For example, a schedule of cron(0 * * * ? *) triggers the synchronizer every hour.
The synchronizer lambda function applies configuration to source servers by reading configuring files from source control, applying any override settings, and then calling APIs for EC2 and DRS to apply the settings for a given source server. This logic is pictured in the figured below.
The settings for the solution can be found in the cfn/lambda/drs-configuration-synchronizer/src/configuration folder.
Launch settings determine how your Drill and Recovery instances will be launched in AWS. They are applied to each source server in DRS. Defaults that should be applied to all source servers are listed in a file named defaults.yml
. Overrides based on source server tags may be specified in files named override_for_tag__{TagKey}__{TagValue}.yml
. NOTE the double underscore between {TagKey} and {TagValue}.
Launch settings are applied in the following order.
- Global defaults (
drs-launch-configurations/defaults.yml
) - Tag overrides (in arbitrary order) (
drs-launch-configurations/override_for_tag__{TagKey}__{TagValue}.yml
)
Example: default launch settings.
defaults.yml
copyPrivateIp: true
copyTags: true
launchDisposition: STARTED
licensing:
osByol: true
targetInstanceTypeRightSizingMethod: BASIC
Example: override copyPrivateIp based on source server tag.
override_for_tag__IPAssignment__dynamic.yml
# disable copying private IP from source server
copyPrivateIp: false
EC2 launch templates determine specific details of how your Drill and Recovery instances will be launched by the DRS service in AWS. They are applied to each source server in DRS. Defaults that should be applied to all source servers are listed in a file named defaults.yml
. Overrides based on source server tags may be specified in files named override_for_tag__{TagKey}__{TagValue}.yml
. NOTE the double underscore between {TagKey} and {TagValue}.
EC2 launch template settings are applied in the following order.
- Global defaults (
ec2-launch-templates/defaults.yml
) - Tag overrides (in arbitrary order) (
ec2-launch-templates/override_for_tag__{TagKey}__{TagValue}.yml
)
The following EC2 launch template settings may be specified. For a list of possible values, please see the LaunchTemplateData
in create_launch_template_version section of the boto3 SDK. For details of how these settings relate to DRS, see the EC2 Launch Template section of the DRS user guide.
IamInstanceProfile
InstanceType
Monitoring
DisableApiTermination
InstanceInitiatedShutdownBehavior
TagSpecifications
CreditSpecification
CpuOptions
CapacityReservationSpecification
LicenseSpecifications
MetadataOptions
PrivateDnsNameOptions
MaintenanceOptions
DisableApiStop
- 'SecurityGroupsIds',
- 'NetworkInterfaces'
The following configuration settings are ignored by the DRS synchronizer if specified in configuration files.
BlockDeviceMappings
EbsOptimized
ElasticGpuSpecifications
ElasticInferenceAccelerators
EnclaveOptions
HibernationOptions
ImageId
InstanceRequirements
KernelId
KeyName
NetworkInterfaces
RamDiskId
SecurityGroups
SecurityGroupsIds
UserData
Example: default EC2 launch template settings.
defaults.yml
MetadataOptions:
HttpEndpoint: enabled
HttpTokens: required
InstanceMetadataTags: enabled
Monitoring:
Enabled: true
Example: disable CloudWatch detailed monitoring based on source server tag.
override_for_tag__monitoring__disabled.yml
# disable monitoring
Monitoring:
Enabled: false
This feature is of particular value for customers with on-premises networks targeting AWS DRS. A customer may configure their AWS DRS networking environment to mirror their on-premises network. The private ip addresses of the origin servers may also need to be the same in the DR environment.
The VPC subnet in which a drill or recovery server is launched is determined by the subnet id specified in the EC2 launch template associated with the DRS source server. The configuration synchronizer automatically populates the subnet id in the EC2 launch template based on the private IP address of the source server and a list of available subnets.
A subnet is considered available based on the following criteria:
- The subnet belongs to a VPC owned by a DRS target AWS account defined in source control
- The VPC of the subnet is tagged with tag key of drstarget and a tag value of true
- The subnet is tagged with tag key of drstarget and a tag value of true
- The private IP address of the source server falls within CIDR block of the subnet
- The private IP address of the source server is not an Amazon reserved IP address.
Replication settings determine how data is replicated from your source servers to AWS. Default replication settings that should be applied to all source servers are listed in a "global defaults" file named defaults.yml
. Defaults may also be specified for each AWS account in files named defaults_for_account_111111111111.yml
where 111111111111
is the AWS account id. Finally, overrides based on source server tags may be specified in files named override_for_tag__{TagKey}__{TagValue}.yml
. NOTE the double underscore between {TagKey} and {TagValue}.
Replication settings are applied in the following order.
- Global defaults (
drs-replication-configurations/defaults.yml
) - Account defaults (
drs-replication-configurations/defaults_for_account_{Account}.yml
) - Tag overrides (in arbitrary order) (
drs-replication-configurations/override_for_tag__{TagKey}__{TagValue}.yml
)
The following replication settings may be specified. For a list of possible values, please see the DRS update_replication_configuration section of the boto3 SDK.
associateDefaultSecurityGroup
bandwidthThrottling
createPublicIP
dataPlaneRouting
defaultLargeStagingDiskType
ebsEncryption
ebsEncryptionKeyArn
replicationServerInstanceType
replicationServersSecurityGroupsIDs
stagingAreaSubnetId
stagingAreaTags
useDedicatedReplicationServer
The following configuration settings are ignored by the DRS synchronizer if specified in configuration files.
PitPolicy
Example of a “defaults” file stored in source control.
defaults.yml
AssociateDefaultSecurityGroup: true
BandwidthThrottling: 0
CreatePublicIP: false
DataPlaneRouting:
Value: PRIVATE_IP
DefaultLargeStagingDiskType:
Value: GP3
ReplicationServerInstanceType: t3.small
EbsEncryption:
Value: CUSTOM
StagingAreaTags: {}
Tags: {}
UseDedicatedReplicationServer: false
Example of defaults specified for servers in AWS account 111111111111
.
defaults_for_account_11111111111.yml
EbsEncryptionKeyArn: arn:aws:kms:us-east-1:111111111111:key/507155b7-550a-4a58-a78f-2d5077df8267
ReplicationServersSecurityGroupsIDs:
- sg-cb38b29593aa2d8c6f
StagingAreaSubnetId:
- subnet-3948f4ba666ae787dd
Example: override bandwidth throttling based on source server tag.
override_for_tag__bandwidth-throttling__1000.yml
# limit to 1 Gbps
BandwidthThrottling: 1000
Tags for DRS source servers may be applied to source servers by listing them in the file named server-tag-mapping.csv.
The first column specifies the hostname of the DRS source server. The remaining columns specify tag keys and values for each server.
The following example server-tag-mapping.csv
shows how two tags, priority-group
and pci
, may be applied to DRS source servers.
Name | priority-group | pci |
---|---|---|
SERVERA | 0.1 | true |
SERVERB | 0.1 | false |
DRS synchronizer features may be disabled for a given DRS source server by listing that server's hostname in the file named config-sync-exclusions.csv
.
If you want to disable a feature for all servers, then only one entry should be made in this file with the Name set to *
.
The first column specifies the hostname of the DRS source server. The remaining columns specify features of the DRS synchronizer that should be disabled for the given server. If a given source server is not listed in this file, then all features are enabled for that server.
The following example config-sync-exclusions.csv
will disable all features for SERVERB
and only disable networking configuration for SERVERA
.
Name | ExcludeAll | ExcludeNetworkConfiguration |
---|---|---|
SERVERA | false | true |
SERVERB | true |
You can execute a dry run of the solution by setting Name to *
and ExcludeAll to true
.
Name | ExcludeAll | ExcludeNetworkConfiguration |
---|---|---|
* | true |
You can exclude automatic network configuration for all servers by setting Name to *
and by setting ExcludeAll
to false
, and ExcludeNetworkConfiguration
to true
.
Name | ExcludeAll | ExcludeNetworkConfiguration |
---|---|---|
* | false | true |
Feature | Description |
---|---|
ExcludeAll |
Skip processing of this source server. Overrides all other features. |
ExcludeNetworkConfiguration |
1. Do not try to find a matching subnet. 2. Do not set subnet/security group on network interface. 3. Set copyPrivateIp=false |
Error reports for each run of the synchronizer may be sent to an SNS topic for further investigation by a human. The first 10 errors/warnings occurring within a single execution of the synchronizer are included in the SNS notification. Additional errors may be viewed by inspecting CloudWatch logs.
Example of an error report:
Time synchronizer started: 2022-11-07 17:59:46 UTC
Time synchronizer finished: 2022-11-07 17:59:57 UTC
Duration: 00:00:11
Servers processed: 218
First 10, of 24 total error(s)/warnings(s):
01. {"level":"WARNING","message":"could not find VPC security group for subnet; ignoring subnet","location":"create_subnet_cidr_mapping:249","timestamp":"2022-11-10 20:10:50,944+0000","service":"drs-configuration-synchronizer","account":"111111111111","subnet_id":"subnet-abcdef11111111111","subnet_cidr":"10.0.0.0/24","vpc_id":"vpc-abcdef11111111111","xray_trace_id":"1-636d5ac7-0e816f6d01363b837b6e9984"}
02. {"level":"WARNING","message":"could not find VPC security group for subnet; ignoring subnet","location":"create_subnet_cidr_mapping:249","timestamp":"2022-11-10 20:10:51,062+0000","service":"drs-configuration-synchronizer","account":"111111111111","subnet_id":"subnet-abcdef11111111111","subnet_cidr":"10.254.0.0/19","vpc_id":"vpc-abcdef11111111111","xray_trace_id":"1-636d5ac7-0e816f6d01363b837b6e9984"}
03. {"level":"WARNING","message":"cannot find an ip address that maps to a target subnet","location":"synchronize_launch_template:595","timestamp":"2022-11-10 20:10:51,978+0000","service":"drs-configuration-synchronizer","account":"111111111111","server":"s-abcdef11111111111","host":"myhost1","xray_trace_id":"1-636d5ac7-0e816f6d01363b837b6e9984"}
04. {"level":"WARNING","message":"cannot find an ip address that maps to a target subnet","location":"synchronize_launch_template:595","timestamp":"2022-11-10 20:10:53,229+0000","service":"drs-configuration-synchronizer","account":"222222222222","server":"s-abcdef11111111111","host":"myhost2","xray_trace_id":"1-636d5ac7-0e816f6d01363b837b6e9984"}
05. {"level":"WARNING","message":"cannot find an ip address that maps to a target subnet","location":"synchronize_launch_template:595","timestamp":"2022-11-10 20:10:54,041+0000","service":"drs-configuration-synchronizer","account":"222222222222","server":"s-abcdef11111111111","host":"myhost3","xray_trace_id":"1-636d5ac7-0e816f6d01363b837b6e9984"}
....
A specialized "inventory report" is generated for each execution of the synchronizer. This report contains information
each DRS source servers processed and information about the target VPC subnet configured in the launch template for the
source server. This report is uploaded to Amazon S3 bucket under key configuration-synchronizer-report.csv
.
Example of an inventory report:
AwsAccountId | SourceServerId | Hostname | ExcludeNetworkConfiguration | CopyPrivateIp | SourceServerIp | LaunchTemplateIp | LaunchTemplateSubnet | LaunchTemplateSecurityGroups |
---|---|---|---|---|---|---|---|---|
111111111111 | s-abcdef11111111111 | host123 | false | true | 10.0.0.5 | 10.0.0.5 | subnet-abcdef11111111111 | sg-abcdef11111111111 |
222222222222 | s-abcdef22222222222 | hostabc | true | false | 172.22.0.1 | 10.1.121.31 | subnet-abcdef11111111111 | sg-abcdef11111111111 |
Automated tests are written for the pytest framework library. Execute tests by running the following commands.
- Python 3.8
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt
python -m venv .venv
. .venv/bin/activate
python -m pip install -r requirements.txt
# install testing dependencies
python -m pip install -r requirements-dev.txt
# run all tests
python -m pytest -v