Launch template encryption of root block device using explicit KMS key

I’m trying to enable encryption of root block devices in an AWS launch template using an explicit customer-managed KMS CMK using Terraform v0.14.3 and AWS provider 3.22.0 on macOS.

It only seems to work if I do NOT specify the key_key_id in the launch template block device ebs configuration block (or if I set it to use the alias/aws/ebs AWS-managed CMK).

When using my own CMK the EC2 instance never initialises and it just terminates before startup.

I don’t suppose anyone has encountered this before? Is this a failure in my understanding of AWS launch template block device configuration, or is there something funky with the AWS provider perhaps?

Pastebin of a minimal example is at Encryption root block device with explicit customer-managed KMS CMK using launch template - Pastebin.com.

variable "unique_example_string" {
  type        = string
  default     = "mytest123"
  description = "Unique string to avoid resource naming conflicts in order to allow the example to function"
}

resource "aws_vpc" "vpc" {
  cidr_block = "192.168.0.0/22"
}

data "aws_availability_zones" "azs" {
  state = "available"
}

resource "aws_subnet" "subnet_az1" {
  availability_zone = data.aws_availability_zones.azs.names[0]
  cidr_block        = "192.168.0.0/24"
  vpc_id            = aws_vpc.vpc.id
}

resource "aws_security_group" "sg" {
  name_prefix = var.unique_example_string
  vpc_id      = aws_vpc.vpc.id
}

data "aws_ami" "ami" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "name"
    values = ["amzn2-ami-ecs-hvm-2.0.*"]
  }
  filter {
    name   = "root-device-type"
    values = ["ebs"]
  }
  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
  filter {
    name   = "architecture"
    values = ["x86_64"]
  }
}

data "aws_region" "current" {}

data "aws_caller_identity" "current" {}

# Policy copied and adapted from alias/aws/ebs KMS key.
data "aws_iam_policy_document" "kms_policy" {
  statement {
    sid    = "Allow access through EBS for all principals in the account that are authorized to use EBS"
    effect = "Allow"
    principals {
      type        = "AWS"
      identifiers = ["*"]
    }
    actions = [
      # Tried both with and without kms:* action (no change in result).
      "kms:Encrypt",
      "kms:Decrypt",
      "kms:ReEncrypt*",
      "kms:GenerateDataKey*",
      "kms:CreateGrant",
      "kms:DescribeKey"
    ]
    # Tried both with and without conditions (no change in result).
    condition {
      test     = "StringEquals"
      variable = "kms:CallerAccount"
      values   = [data.aws_caller_identity.current.account_id]
    }
    condition {
      test     = "StringEquals"
      variable = "kms:ViaService"
      values   = ["ec2.${data.aws_region.current.name}.amazonaws.com"]
    }
  }
  statement {
    sid    = "Enable IAM User Permissions"
    effect = "Allow"
    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
    }
    actions   = ["kms:*"]
    resources = ["*"]
  }
}

resource "aws_kms_key" "kms" {
  description = var.unique_example_string
  # Tried both with and without an explicit policy (no change in result).
  policy      = data.aws_iam_policy_document.kms_policy.json
}

resource "aws_launch_template" "example" {
  name_prefix            = var.unique_example_string
  ebs_optimized          = true
  image_id               = data.aws_ami.ami.image_id
  instance_type          = "t3.nano"
  vpc_security_group_ids = [aws_security_group.sg.id]

  block_device_mappings {
    device_name = data.aws_ami.ami.root_device_name
    ebs {
      delete_on_termination = true
      encrypted             = true
      volume_type           = "gp2"
      volume_size           = 30
      # Tried both with and without kms_key_id (only works WITHOUT kms_key_id or when pointing to alias/aws/ebs).
      #kms_key_id            = aws_kms_key.kms.arn
    }
  }
}

resource "aws_autoscaling_group" "example" {
  name_prefix         = var.unique_example_string
  vpc_zone_identifier = [aws_subnet.subnet_az1.id]
  min_size            = 1
  max_size            = 1

  launch_template {
    id      = aws_launch_template.example.id
    version = "$Latest"
  }
}

As discussed on gitter additional policies are required.