feat(encryption): implement AWS KMS integration with encryption provider and update related configurations
This commit is contained in:
@@ -1 +0,0 @@
|
||||
../repository.vault
|
||||
@@ -138,6 +138,10 @@ encryption_volumes:
|
||||
mount_service_before: snap.microk8s.daemon-kubelite.service
|
||||
mount_service_wantedby: snap.microk8s.daemon-kubelite.service
|
||||
mount_permission: "0755"
|
||||
encryption_aws_access_key_id: "{{ lookup('env', 'KMS_ACCESS_KEY') }}"
|
||||
encryption_aws_secret_access_key: "{{ lookup('env', 'KMS_SECRET_KEY') }}"
|
||||
encryption_kms_arn: "arn:aws:kms:eu-west-1:001604727293:key/977d08fd-8230-40bf-8a4f-d8a3264c5990"
|
||||
encryption_kms_socket: /var/run/kmsplugin/socket.sock
|
||||
|
||||
# Kubernetes specific settings
|
||||
microk8s_version: 1.29
|
||||
@@ -149,6 +153,7 @@ microk8s_alt_names: "{{ hostname }}"
|
||||
microk8s_issuer_email: c.alexandre.pires@alexpires.me
|
||||
microk8s_encryption_cfg: /mnt/microk8s_config/microk8s_encryption.yaml
|
||||
microk8s_encryption_secret: "{{ lookup('env', 'MICROK8S_ENCRYPTION_SECRET') }}"
|
||||
microk8s_encryption_kms_socket: /var/run/kmsplugin/socket.sock
|
||||
microk8s_users:
|
||||
- username: operator
|
||||
enabled: true
|
||||
|
||||
@@ -8,3 +8,5 @@
|
||||
tags:
|
||||
- roles
|
||||
- roles::encryption
|
||||
- roles::encryption::kms
|
||||
- roles::encryption::volume
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
encryption_volumes: []
|
||||
encryption_volumes_path: /var/lib/encrypted_volumes
|
||||
encryption_volumes_default_size: 1G
|
||||
|
||||
encryption_aws_access_key_id:
|
||||
encryption_aws_secret_access_key:
|
||||
encryption_kms_arn:
|
||||
encryption_kms_region: eu-west-1
|
||||
encryption_kms_socket: /var/run/kmsplugin/socket.sock
|
||||
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,57 @@
|
||||
- name: Check if required facts are set
|
||||
ansible.builtin.fail:
|
||||
msg: "The following variables are required: encryption_aws_access_key_id, encryption_aws_secret_access_key, encryption_kms_arn"
|
||||
when:
|
||||
- encryption_aws_access_key_id is not defined
|
||||
- encryption_aws_secret_access_key is not defined
|
||||
- encryption_kms_arn is not defined
|
||||
|
||||
- name: Copy aws-encryption-provider binary to the host
|
||||
become: true
|
||||
ansible.builtin.copy:
|
||||
src: aws-encryption-provider
|
||||
dest: /usr/local/bin/aws-encryption-provider
|
||||
mode: '0755'
|
||||
|
||||
- name: Copy start script to the host
|
||||
become: true
|
||||
ansible.builtin.template:
|
||||
src: start-encryption-provider.sh.j2
|
||||
dest: /usr/local/bin/start-encryption-provider.sh
|
||||
mode: '0755'
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Create KMS socket directory
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
path: /var/run/kmsplugin
|
||||
state: directory
|
||||
mode: '0755'
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Create systemd service file for aws-encryption-provider
|
||||
become: true
|
||||
ansible.builtin.template:
|
||||
src: aws-encryption-provider.service.j2
|
||||
dest: /etc/systemd/system/aws-encryption-provider.service
|
||||
mode: '0644'
|
||||
|
||||
- name: Reload systemd daemon
|
||||
become: true
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
name: aws-encryption-provider
|
||||
|
||||
- name: Enable aws-encryption-provider service
|
||||
become: true
|
||||
ansible.builtin.systemd:
|
||||
name: aws-encryption-provider
|
||||
enabled: true
|
||||
|
||||
- name: Start aws-encryption-provider service
|
||||
become: true
|
||||
ansible.builtin.systemd:
|
||||
name: aws-encryption-provider
|
||||
state: started
|
||||
@@ -5,8 +5,12 @@
|
||||
name:
|
||||
- cryptsetup
|
||||
- curl
|
||||
- libc6
|
||||
state: present
|
||||
when: ansible_os_family == 'Debian'
|
||||
tags:
|
||||
- roles::encryption::packages
|
||||
- roles::encryption::volume
|
||||
|
||||
- name: Create folder to store volume
|
||||
become: true
|
||||
@@ -14,6 +18,8 @@
|
||||
path: "{{ encryption_volumes_path }}"
|
||||
state: directory
|
||||
mode: "0750"
|
||||
tags:
|
||||
- roles::encryption::volume
|
||||
|
||||
- name: Copy required scripts
|
||||
become: true
|
||||
@@ -24,9 +30,19 @@
|
||||
with_items:
|
||||
- "open_volume"
|
||||
- "read_system_id"
|
||||
tags:
|
||||
- roles::encryption::volume
|
||||
|
||||
- name: Create encrypted volumes
|
||||
ansible.builtin.include_tasks: volume.yml
|
||||
loop: "{{ encryption_volumes }}"
|
||||
loop_control:
|
||||
loop_var: item
|
||||
tags:
|
||||
- roles::encryption::volume
|
||||
|
||||
- name: Create KMS service
|
||||
ansible.builtin.include_tasks: kms.yml
|
||||
when: encryption_aws_access_key_id is defined and encryption_aws_secret_access_key is defined and encryption_kms_arn is defined
|
||||
tags:
|
||||
- roles::encryption::kms
|
||||
|
||||
@@ -89,45 +89,17 @@
|
||||
|
||||
- name: Create service to fetch key file and open LUKS device
|
||||
become: true
|
||||
ansible.builtin.copy:
|
||||
ansible.builtin.template:
|
||||
src: key_fetch.service.j2
|
||||
dest: /etc/systemd/system/{{ key_fetch_service }}
|
||||
mode: "0644"
|
||||
content: |
|
||||
[Unit]
|
||||
Description={{ item.name }} key fetch service
|
||||
After={{ fetch_key_service_after }}
|
||||
Before={{ fetch_key_service_before }}
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=true
|
||||
ExecStart=/usr/local/bin/open_volume "{{ key_server }}" {{ disk_image_path }} {{ device_name }}
|
||||
ExecStop=/usr/sbin/cryptsetup close {{ device_name }}
|
||||
|
||||
[Install]
|
||||
WantedBy={{ fetch_key_service_wantedby }}
|
||||
|
||||
- name: Create service to mount the local filesystem
|
||||
become: true
|
||||
ansible.builtin.copy:
|
||||
ansible.builtin.template:
|
||||
src: mount.service.j2
|
||||
dest: /etc/systemd/system/{{ mount_service }}
|
||||
mode: "0644"
|
||||
content: |
|
||||
[Unit]
|
||||
|
||||
Description={{ item.name }} mount service
|
||||
After={{ key_fetch_service }}
|
||||
Requires={{ key_fetch_service }}
|
||||
Before={{ mount_service_before }}
|
||||
|
||||
[Mount]
|
||||
What=/dev/mapper/{{ device_name }}
|
||||
Where={{ mount_point }}
|
||||
Type=ext4
|
||||
Options=defaults
|
||||
|
||||
[Install]
|
||||
WantedBy={{ mount_service_wantedby }}
|
||||
|
||||
- name: Reload systemd daemon
|
||||
become: true
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=AWS Encryption Provider
|
||||
After=network.target
|
||||
Before=snap.microk8s.daemon-kubelite.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/start-encryption-provider.sh
|
||||
Restart=on-failure
|
||||
User=root
|
||||
|
||||
[Install]
|
||||
WantedBy=snap.microk8s.daemon-kubelite.service
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description={{ item.name }} key fetch service
|
||||
After={{ fetch_key_service_after }}
|
||||
Before={{ fetch_key_service_before }}
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=true
|
||||
ExecStart=/usr/local/bin/open_volume "{{ key_server }}" {{ disk_image_path }} {{ device_name }}
|
||||
ExecStop=/usr/sbin/cryptsetup close {{ device_name }}
|
||||
|
||||
[Install]
|
||||
WantedBy={{ fetch_key_service_wantedby }}
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description={{ item.name }} mount service
|
||||
After={{ key_fetch_service }}
|
||||
Requires={{ key_fetch_service }}
|
||||
Before={{ mount_service_before }}
|
||||
|
||||
[Mount]
|
||||
What=/dev/mapper/{{ device_name }}
|
||||
Where={{ mount_point }}
|
||||
Type=ext4
|
||||
Options=defaults
|
||||
|
||||
[Install]
|
||||
WantedBy={{ mount_service_wantedby }}
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
# This script is used to start the encryption provider for the application.
|
||||
# Managed by Ansible.
|
||||
export AWS_ACCESS_KEY_ID={{ encryption_aws_access_key_id }}
|
||||
export AWS_SECRET_ACCESS_KEY={{ encryption_aws_secret_access_key }}
|
||||
/usr/local/bin/aws-encryption-provider --key={{ encryption_kms_arn }} --region={{ encryption_kms_region }} --listen={{ encryption_kms_socket }}
|
||||
@@ -39,3 +39,4 @@ microk8s_iac_user: "provision"
|
||||
|
||||
microk8s_encryption_secret: "a13labs"
|
||||
microk8s_encryption_cfg: "/etc/microk8s_encryption.yaml"
|
||||
microk8s_encryption_kms_socket:
|
||||
|
||||
@@ -7,21 +7,8 @@
|
||||
|
||||
- name: Create encryption configuration
|
||||
become: true
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
---
|
||||
apiVersion: apiserver.config.k8s.io/v1
|
||||
kind: EncryptionConfiguration
|
||||
resources:
|
||||
- resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
providers:
|
||||
- aescbc:
|
||||
keys:
|
||||
- name: k8s-crypto
|
||||
secret: {{ microk8s_encryption_secret }}
|
||||
- identity: {}
|
||||
ansible.builtin.template:
|
||||
src: encryption-provider-config.yml.j2
|
||||
dest: "{{ microk8s_encryption_cfg }}"
|
||||
mode: "0600"
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
apiVersion: apiserver.config.k8s.io/v1
|
||||
kind: EncryptionConfiguration
|
||||
resources:
|
||||
- resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
providers:
|
||||
{% if microk8s_encryption_kms_socket is defined %}
|
||||
- kms:
|
||||
apiVersion: v2
|
||||
name: aws-encryption-provider
|
||||
endpoint: unix://{{ microk8s_encryption_kms_socket }}
|
||||
timeout: 3s
|
||||
{% endif %}
|
||||
- aescbc:
|
||||
keys:
|
||||
- name: k8s-crypto
|
||||
secret: {{ microk8s_encryption_secret }}
|
||||
- identity: {}
|
||||
@@ -7,3 +7,6 @@ USER_PASSWORD_OPERATOR=$USER_PASSWORD_OPERATOR
|
||||
ANSIBLE_FORCE_COLOR=True
|
||||
BUCKET_SUFFIX=$BUCKET_SUFFIX
|
||||
MICROK8S_ENCRYPTION_SECRET=$MICROK8S_ENCRYPTION_SECRET
|
||||
KMS_ACCESS_KEY=$KMS_ACCESS_KEY
|
||||
KMS_SECRET_KEY=$KMS_SECRET_KEY
|
||||
KMS_KEY_ARN=$KMS_KEY_ARN
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
data "aws_iam_policy_document" "kms_key_policy" {
|
||||
statement {
|
||||
sid = "Enable IAM User Permissions"
|
||||
effect = "Allow"
|
||||
actions = ["kms:*"]
|
||||
resources = ["*"]
|
||||
|
||||
principals {
|
||||
type = "AWS"
|
||||
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
|
||||
}
|
||||
}
|
||||
|
||||
statement {
|
||||
sid = "Allow IAM User Access"
|
||||
effect = "Allow"
|
||||
actions = [
|
||||
"kms:Encrypt",
|
||||
"kms:Decrypt",
|
||||
"kms:ReEncrypt*",
|
||||
"kms:GenerateDataKey*",
|
||||
"kms:DescribeKey"
|
||||
]
|
||||
resources = ["*"]
|
||||
|
||||
principals {
|
||||
type = "AWS"
|
||||
identifiers = [aws_iam_user.k8s_secrets_user.arn]
|
||||
}
|
||||
|
||||
condition {
|
||||
# Only allow from specific IP addresses
|
||||
test = "IpAddress"
|
||||
variable = "aws:SourceIp"
|
||||
values = ["${join(",", local.instance_ips)}"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_kms_key" "k8s_secrets" {
|
||||
description = "KMS key for encrypting Kubernetes secrets"
|
||||
deletion_window_in_days = 30
|
||||
enable_key_rotation = true
|
||||
|
||||
policy = data.aws_iam_policy_document.kms_key_policy.json
|
||||
}
|
||||
|
||||
resource "aws_iam_user" "k8s_secrets_user" {
|
||||
name = "alexpires-me-microk8s"
|
||||
}
|
||||
|
||||
resource "aws_iam_access_key" "k8s_secrets_user_key" {
|
||||
user = aws_iam_user.k8s_secrets_user.name
|
||||
}
|
||||
|
||||
data "aws_iam_policy_document" "k8s_secrets_user_policy" {
|
||||
statement {
|
||||
effect = "Allow"
|
||||
|
||||
actions = [
|
||||
"kms:Encrypt",
|
||||
"kms:Decrypt",
|
||||
"kms:ReEncrypt*",
|
||||
"kms:GenerateDataKey*",
|
||||
"kms:DescribeKey"
|
||||
]
|
||||
|
||||
resources = [aws_kms_key.k8s_secrets.arn]
|
||||
condition {
|
||||
# Only allow from specific IP addresses
|
||||
test = "IpAddress"
|
||||
variable = "aws:SourceIp"
|
||||
values = ["${join(",", local.instance_ips)}"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_iam_user_policy" "k8s_secrets_user_policy" {
|
||||
name = "alexpires-me-microk8s-policy"
|
||||
user = aws_iam_user.k8s_secrets_user.name
|
||||
policy = data.aws_iam_policy_document.k8s_secrets_user_policy.json
|
||||
}
|
||||
|
||||
data "aws_caller_identity" "current" {}
|
||||
|
||||
locals {
|
||||
instance_ips = [
|
||||
"${local.vps_1.ip}/32",
|
||||
]
|
||||
|
||||
vps_1 = {
|
||||
id = data.terraform_remote_state.contabo.outputs.instances[0].id
|
||||
name = data.terraform_remote_state.contabo.outputs.instances[0].name
|
||||
ip = data.terraform_remote_state.contabo.outputs.instances[0].ip_config[0].v4[0].ip
|
||||
}
|
||||
}
|
||||
|
||||
data "terraform_remote_state" "contabo" {
|
||||
backend = "s3"
|
||||
config = {
|
||||
bucket = "a13labs.infra.eu"
|
||||
key = "contabo.core.infra.tfstate"
|
||||
region = "eu-west-1"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user