From 4fcef5e09bbd8dfae498f3e5f109d4062715de3d Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 22 Feb 2019 09:18:00 -0800 Subject: [PATCH] data/aws: Encrypt the AMI used by the bootstrap and master machines This is a quick hack to get encrypted masters. Ideally we'd want to deregister these on bootstrap-teardown, but handling that nicely will be easier after some cleanups from [1]. As it stands, we'll deregister this as part of the general cluster teardown. Because we don't set kms_key_id [2] we get "the default AWS KMS Key" (according to [2]). AWS docs are not particularly clear about whether users can configure the default key for their account/region to override that default, although it is clear that it defaults to an AWS-managed CMK [3] and that the alias for AMI encryption is alias/aws/ebs [4]. If there is no way to override alias/aws/ebs, we'll probably eventially need to expose kms_key_id to users. [1]: https://github.com/openshift/installer/pull/1148 [2]: https://www.terraform.io/docs/providers/aws/r/ami_copy.html#kms_key_id [3]: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#aws-managed-cmk [4]: https://aws.amazon.com/blogs/security/how-to-create-a-custom-ami-with-encrypted-amazon-ebs-snapshots-and-share-it-with-other-accounts-and-regions/ --- data/data/aws/main.tf | 17 +++++++++++++++-- data/data/aws/variables-aws.tf | 5 ++--- docs/user/aws/install.md | 6 ++++++ pkg/destroy/aws/aws.go | 17 +++++++++++++++++ pkg/tfvars/aws/aws.go | 4 ++-- 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/data/data/aws/main.tf b/data/data/aws/main.tf index 72582c0cc06..093a3f0272e 100644 --- a/data/data/aws/main.tf +++ b/data/data/aws/main.tf @@ -11,7 +11,7 @@ provider "aws" { module "bootstrap" { source = "./bootstrap" - ami = "${var.aws_ec2_ami_override}" + ami = "${aws_ami_copy.main.id}" instance_type = "${var.aws_bootstrap_instance_type}" cluster_id = "${var.cluster_id}" ignition = "${var.ignition_bootstrap}" @@ -40,7 +40,7 @@ module "masters" { subnet_ids = "${module.vpc.private_subnet_ids}" target_group_arns = "${module.vpc.aws_lb_target_group_arns}" target_group_arns_length = "${module.vpc.aws_lb_target_group_arns_length}" - ec2_ami = "${var.aws_ec2_ami_override}" + ec2_ami = "${aws_ami_copy.main.id}" user_data_ign = "${var.ignition_master}" } @@ -77,3 +77,16 @@ module "vpc" { tags = "${local.tags}" } + +resource "aws_ami_copy" "main" { + name = "${var.cluster_id}-master" + source_ami_id = "${var.aws_ami}" + source_ami_region = "${var.aws_region}" + encrypted = true + + tags = "${merge(map( + "Name", "${var.cluster_id}-master", + "sourceAMI": "${var.aws_ami}", + "sourceRegion": "${var.aws_region}", + ), local.tags)}" +} diff --git a/data/data/aws/variables-aws.tf b/data/data/aws/variables-aws.tf index e7530e54374..3f0f5902763 100644 --- a/data/data/aws/variables-aws.tf +++ b/data/data/aws/variables-aws.tf @@ -17,10 +17,9 @@ variable "aws_master_instance_type" { description = "Instance type for the master node(s). Example: `m4.large`." } -variable "aws_ec2_ami_override" { +variable "aws_ami" { type = "string" - description = "(optional) AMI override for all nodes. Example: `ami-foobar123`." - default = "" + description = "AMI for all nodes. An encrypted copy of this AMI will be used. Example: `ami-foobar123`." } variable "aws_extra_tags" { diff --git a/docs/user/aws/install.md b/docs/user/aws/install.md index e5dfac51690..117510ee242 100644 --- a/docs/user/aws/install.md +++ b/docs/user/aws/install.md @@ -33,6 +33,11 @@ INFO Access the OpenShift web-console here: https://console-openshift-console.ap INFO Login to the console with user: kubeadmin, password: XXXX ``` +This creates an encrypted AMI for the bootstrap and control-plane machines. +The encrypted AMI is [copied][encrypted-copy] from the AMI configured in the control-plane machine-API provider spec, which is RHCOS by default. +The encryption uses the default EBS key for your target account and region (`aws kms describe-key --key-id alias/aws/ebs`). +The encrypted AMI is deregistered by `destroy cluster`. + ### Running Cluster In Route53, there will be a new, private hosted zone (for internal lookups): @@ -56,3 +61,4 @@ The OpenShift console is available via the kubeadmin login provided by the insta ![OpenShift web console](images/install_console.png) [cloud-install]: https://cloud.openshift.com/clusters/install +[encrypted-copy]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIEncryption.html#create-ami-encrypted-root-snapshot diff --git a/pkg/destroy/aws/aws.go b/pkg/destroy/aws/aws.go index 273d8e300ea..574e6286055 100644 --- a/pkg/destroy/aws/aws.go +++ b/pkg/destroy/aws/aws.go @@ -455,6 +455,8 @@ func deleteEC2(session *session.Session, arn arn.ARN, logger logrus.FieldLogger) return deleteEC2DHCPOptions(client, id, logger) case "elastic-ip": return deleteEC2ElasticIP(client, id, logger) + case "image": + return deleteEC2Image(client, id, logger) case "instance": return deleteEC2Instance(client, iam.New(session), id, logger) case "internet-gateway": @@ -491,6 +493,21 @@ func deleteEC2DHCPOptions(client *ec2.EC2, id string, logger logrus.FieldLogger) return nil } +func deleteEC2Image(client *ec2.EC2, id string, logger logrus.FieldLogger) error { + _, err := client.DeregisterImage(&ec2.DeregisterImageInput{ + ImageId: &id, + }) + if err != nil { + if err.(awserr.Error).Code() == "InvalidAMIID.NotFound" { + return nil + } + return err + } + + logger.Info("Deleted") + return nil +} + func deleteEC2ElasticIP(client *ec2.EC2, id string, logger logrus.FieldLogger) error { _, err := client.ReleaseAddress(&ec2.ReleaseAddressInput{ AllocationId: aws.String(id), diff --git a/pkg/tfvars/aws/aws.go b/pkg/tfvars/aws/aws.go index a5fb07c4a88..8a3111dc756 100644 --- a/pkg/tfvars/aws/aws.go +++ b/pkg/tfvars/aws/aws.go @@ -11,7 +11,7 @@ import ( ) type config struct { - EC2AMIOverride string `json:"aws_ec2_ami_override,omitempty"` + AMI string `json:"aws_ami"` ExtraTags map[string]string `json:"aws_extra_tags,omitempty"` BootstrapInstanceType string `json:"aws_bootstrap_instance_type,omitempty"` MasterInstanceType string `json:"aws_master_instance_type,omitempty"` @@ -54,7 +54,7 @@ func TFVars(masterConfig *v1beta1.AWSMachineProviderConfig) ([]byte, error) { cfg := &config{ Region: masterConfig.Placement.Region, ExtraTags: tags, - EC2AMIOverride: *masterConfig.AMI.ID, + AMI: *masterConfig.AMI.ID, BootstrapInstanceType: fmt.Sprintf("%s.large", instanceClass), MasterInstanceType: masterConfig.InstanceType, Size: *rootVolume.EBS.VolumeSize,