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_before: snap.microk8s.daemon-kubelite.service
|
||||||
mount_service_wantedby: snap.microk8s.daemon-kubelite.service
|
mount_service_wantedby: snap.microk8s.daemon-kubelite.service
|
||||||
mount_permission: "0755"
|
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
|
# Kubernetes specific settings
|
||||||
microk8s_version: 1.29
|
microk8s_version: 1.29
|
||||||
@@ -149,6 +153,7 @@ microk8s_alt_names: "{{ hostname }}"
|
|||||||
microk8s_issuer_email: c.alexandre.pires@alexpires.me
|
microk8s_issuer_email: c.alexandre.pires@alexpires.me
|
||||||
microk8s_encryption_cfg: /mnt/microk8s_config/microk8s_encryption.yaml
|
microk8s_encryption_cfg: /mnt/microk8s_config/microk8s_encryption.yaml
|
||||||
microk8s_encryption_secret: "{{ lookup('env', 'MICROK8S_ENCRYPTION_SECRET') }}"
|
microk8s_encryption_secret: "{{ lookup('env', 'MICROK8S_ENCRYPTION_SECRET') }}"
|
||||||
|
microk8s_encryption_kms_socket: /var/run/kmsplugin/socket.sock
|
||||||
microk8s_users:
|
microk8s_users:
|
||||||
- username: operator
|
- username: operator
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|||||||
@@ -8,3 +8,5 @@
|
|||||||
tags:
|
tags:
|
||||||
- roles
|
- roles
|
||||||
- roles::encryption
|
- roles::encryption
|
||||||
|
- roles::encryption::kms
|
||||||
|
- roles::encryption::volume
|
||||||
|
|||||||
@@ -2,3 +2,9 @@
|
|||||||
encryption_volumes: []
|
encryption_volumes: []
|
||||||
encryption_volumes_path: /var/lib/encrypted_volumes
|
encryption_volumes_path: /var/lib/encrypted_volumes
|
||||||
encryption_volumes_default_size: 1G
|
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:
|
name:
|
||||||
- cryptsetup
|
- cryptsetup
|
||||||
- curl
|
- curl
|
||||||
|
- libc6
|
||||||
state: present
|
state: present
|
||||||
when: ansible_os_family == 'Debian'
|
when: ansible_os_family == 'Debian'
|
||||||
|
tags:
|
||||||
|
- roles::encryption::packages
|
||||||
|
- roles::encryption::volume
|
||||||
|
|
||||||
- name: Create folder to store volume
|
- name: Create folder to store volume
|
||||||
become: true
|
become: true
|
||||||
@@ -14,6 +18,8 @@
|
|||||||
path: "{{ encryption_volumes_path }}"
|
path: "{{ encryption_volumes_path }}"
|
||||||
state: directory
|
state: directory
|
||||||
mode: "0750"
|
mode: "0750"
|
||||||
|
tags:
|
||||||
|
- roles::encryption::volume
|
||||||
|
|
||||||
- name: Copy required scripts
|
- name: Copy required scripts
|
||||||
become: true
|
become: true
|
||||||
@@ -24,9 +30,19 @@
|
|||||||
with_items:
|
with_items:
|
||||||
- "open_volume"
|
- "open_volume"
|
||||||
- "read_system_id"
|
- "read_system_id"
|
||||||
|
tags:
|
||||||
|
- roles::encryption::volume
|
||||||
|
|
||||||
- name: Create encrypted volumes
|
- name: Create encrypted volumes
|
||||||
ansible.builtin.include_tasks: volume.yml
|
ansible.builtin.include_tasks: volume.yml
|
||||||
loop: "{{ encryption_volumes }}"
|
loop: "{{ encryption_volumes }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
loop_var: item
|
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
|
- name: Create service to fetch key file and open LUKS device
|
||||||
become: true
|
become: true
|
||||||
ansible.builtin.copy:
|
ansible.builtin.template:
|
||||||
|
src: key_fetch.service.j2
|
||||||
dest: /etc/systemd/system/{{ key_fetch_service }}
|
dest: /etc/systemd/system/{{ key_fetch_service }}
|
||||||
mode: "0644"
|
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
|
- name: Create service to mount the local filesystem
|
||||||
become: true
|
become: true
|
||||||
ansible.builtin.copy:
|
ansible.builtin.template:
|
||||||
|
src: mount.service.j2
|
||||||
dest: /etc/systemd/system/{{ mount_service }}
|
dest: /etc/systemd/system/{{ mount_service }}
|
||||||
mode: "0644"
|
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
|
- name: Reload systemd daemon
|
||||||
become: true
|
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_secret: "a13labs"
|
||||||
microk8s_encryption_cfg: "/etc/microk8s_encryption.yaml"
|
microk8s_encryption_cfg: "/etc/microk8s_encryption.yaml"
|
||||||
|
microk8s_encryption_kms_socket:
|
||||||
|
|||||||
@@ -7,21 +7,8 @@
|
|||||||
|
|
||||||
- name: Create encryption configuration
|
- name: Create encryption configuration
|
||||||
become: true
|
become: true
|
||||||
ansible.builtin.copy:
|
ansible.builtin.template:
|
||||||
content: |
|
src: encryption-provider-config.yml.j2
|
||||||
---
|
|
||||||
apiVersion: apiserver.config.k8s.io/v1
|
|
||||||
kind: EncryptionConfiguration
|
|
||||||
resources:
|
|
||||||
- resources:
|
|
||||||
- secrets
|
|
||||||
- configmaps
|
|
||||||
providers:
|
|
||||||
- aescbc:
|
|
||||||
keys:
|
|
||||||
- name: k8s-crypto
|
|
||||||
secret: {{ microk8s_encryption_secret }}
|
|
||||||
- identity: {}
|
|
||||||
dest: "{{ microk8s_encryption_cfg }}"
|
dest: "{{ microk8s_encryption_cfg }}"
|
||||||
mode: "0600"
|
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
|
ANSIBLE_FORCE_COLOR=True
|
||||||
BUCKET_SUFFIX=$BUCKET_SUFFIX
|
BUCKET_SUFFIX=$BUCKET_SUFFIX
|
||||||
MICROK8S_ENCRYPTION_SECRET=$MICROK8S_ENCRYPTION_SECRET
|
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