Skip to content

Commit

Permalink
Changes for boot drive encryption and CES failover (#570)
Browse files Browse the repository at this point in the history
* Added VNI

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* Added DNS and VSI modification

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* New changes

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* added reserved ip as sec ip

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* CES as Bm changes
Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* protocol_vsi_profile added

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* Modified the conditions

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* desc node change

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* Few changes

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* fix1

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* added subnet id and removed few

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* fixs

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* boot drive change

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* boot drive changes

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* added condition for afm and ces nodes

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* fix

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* Fixed indentation and other fixes
Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* modified output

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* Colocation and VNIc changes

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* Colocation changes for BM

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* Added condition to afm server

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* Updated ldap variable

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* updated condition for protocol vsi

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* Updated changes for ces node expansion

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* Modification for failover

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

* Added condition for tie breaker node

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>

---------

Signed-off-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>
Co-authored-by: Jayesh-Kumar3 <Jayesh.Kumar3@ibm.com>
  • Loading branch information
jayeshh123 and Jayesh-Kumar3 authored Oct 4, 2024
1 parent 1ca4977 commit b395801
Show file tree
Hide file tree
Showing 14 changed files with 910 additions and 197 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Below steps will provision IBM Cloud resources (compute and storage instances in
| Name | Version |
|------|---------|
| <a name="requirement_github"></a> [github](#requirement_github) | 5.41.0 |
| <a name="requirement_ibm"></a> [ibm](#requirement_ibm) | 1.67.1 |
| <a name="requirement_ibm"></a> [ibm](#requirement_ibm) | 1.68.0 |
#### Inputs
Expand Down Expand Up @@ -129,6 +129,7 @@ Below steps will provision IBM Cloud resources (compute and storage instances in
| <a name="input_scale_encryption_admin_password"></a> [scale_encryption_admin_password](#input_scale_encryption_admin_password) | Password that is used for performing administrative operations for the GKLM.The password must contain at least 8 characters and at most 20 characters. For a strong password, at least three alphabetic characters are required, with at least one uppercase and one lowercase letter. Two numbers, and at least one special character from this(~@_+:). Make sure that the password doesn't include the username. Visit this [page](https://www.ibm.com/docs/en/gklm/3.0.1?topic=roles-password-policy) to know more about password policy of GKLM. | `string` |
| <a name="input_scale_encryption_admin_username"></a> [scale_encryption_admin_username](#input_scale_encryption_admin_username) | The default Admin username for Security Key Lifecycle Manager(GKLM). | `string` |
| <a name="input_scale_encryption_enabled"></a> [scale_encryption_enabled](#input_scale_encryption_enabled) | To enable the encryption for the filesystem. Select true or false | `bool` |
| <a name="input_scale_encryption_type"></a> [scale_encryption_type](#input_scale_encryption_type) | To enable filesystem encryption, specify either 'key_protect' or 'gklm'. If neither is specified, the default value will be 'null' and encryption is disabled | `string` |
| <a name="input_spectrumscale_rpms_path"></a> [spectrumscale_rpms_path](#input_spectrumscale_rpms_path) | Path that contains IBM Spectrum Scale product cloud rpms. | `string` |
| <a name="input_storage_bare_metal_osimage_id"></a> [storage_bare_metal_osimage_id](#input_storage_bare_metal_osimage_id) | Image Id to use for provisioning the storage Baremetal cluster instances. | `string` |
| <a name="input_storage_bare_metal_osimage_name"></a> [storage_bare_metal_osimage_name](#input_storage_bare_metal_osimage_name) | Image name to use for provisioning the storage Baremetal cluster. | `string` |
Expand Down
148 changes: 86 additions & 62 deletions ibmcloud_scale_templates/sub_modules/instance_template/main.tf

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ output "storage_cluster_with_data_volume_mapping" {
}

output "storage_cluster_desc_instance_ids" {
value = module.storage_cluster_tie_breaker_instance.instance_ids
value = module.storage_cluster_tie_breaker_instance[*].instance_ids
description = "Storage cluster desc instance id."
}

output "storage_cluster_desc_instance_private_ips" {
value = module.storage_cluster_tie_breaker_instance.instance_private_ips
value = module.storage_cluster_tie_breaker_instance[*].instance_private_ips
description = "Private IP address of storage cluster desc instance."
}

output "storage_cluster_desc_data_volume_mapping" {
value = module.storage_cluster_tie_breaker_instance.instance_ips_with_vol_mapping
value = module.storage_cluster_tie_breaker_instance[*].instance_ips_with_vol_mapping
description = "Mapping of storage cluster desc instance ip vs. device path."
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ variable "ldap_server" {
variable "ldap_admin_password" {
type = string
sensitive = true
default = ""
default = "null"
description = "The LDAP administrative password should be 8 to 20 characters long, with a mix of at least three alphabetic characters, including one uppercase and one lowercase letter. It must also include two numerical digits and at least one special character from (~@_+:) are required. It is important to avoid including the username in the password for enhanced security."
}

Expand Down
2 changes: 1 addition & 1 deletion resources/common/scripts/prepare_scale_inv_ini.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,9 @@ def prepare_ansible_playbook(hosts_config, cluster_config, cluster_key_file):
- {{ role: mrot_config, when: enable_mrot }}
- {{ role: nfs_prepare, when: enable_ces }}
- {{ role: nfs_install, when: "enable_ces and scale_packages_installed is false" }}
- {{ role: nfs_ic_failover, when: enable_ces }}
- {{ role: nfs_configure, when: enable_ces }}
- {{ role: nfs_route_configure, when: enable_ces }}
- {{ role: nfs_ic_failover, when: enable_ces }}
- {{ role: nfs_verify, when: enable_ces }}
- {{ role: auth_prepare, when: enable_ces }}
- {{ role: auth_configure, when: enable_ldap or enable_ces }}
Expand Down
61 changes: 53 additions & 8 deletions resources/ibmcloud/compute/afm_vsi/afm_vsi.tf
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ variable "resource_group_id" {}
variable "resource_tags" {}
variable "scale_firewall_rules_enabled" {}
variable "afm_server_type" {}

variable "bms_boot_drive_encryption" {}
variable "storage_private_key" {}

data "template_file" "metadata_startup_script_vsi" {
template = <<EOF
Expand Down Expand Up @@ -203,9 +204,16 @@ resource "ibm_dns_resource_record" "ptr_itself_vsi" {
depends_on = [ibm_dns_resource_record.a_itself_vsi]
}

#
####################### Bare Metal Server ####################
#
##########################################################################################################################
################ Bare Metal Server ################
##########################################################################################################################
locals {
user_data_vars = {
dns_domain = var.dns_domain,
vsi_meta_private_key = base64encode(var.vsi_meta_private_key),
vsi_meta_public_key = base64encode(var.vsi_meta_public_key)
}
}

data "template_file" "metadata_startup_script_bm" {
template = <<EOF
Expand All @@ -220,7 +228,6 @@ then
package_list="python3 kernel-devel-$(uname -r) kernel-headers-$(uname -r) firewalld numactl make gcc-c++ elfutils-libelf-devel bind-utils iptables-nft nfs-utils elfutils elfutils-devel python3-dnf-plugin-versionlock"
elif grep -q "platform:el8" /etc/os-release
then
subscription-manager repos --enable=rhel-8-for-x86_64-baseos-eus-rpms
package_list="python38 kernel-devel-$(uname -r) kernel-headers-$(uname -r) firewalld numactl jq make gcc-c++ elfutils-libelf-devel bind-utils iptables nfs-utils elfutils elfutils-devel python3-dnf-plugin-versionlock"
fi
Expand Down Expand Up @@ -323,10 +330,48 @@ resource "ibm_is_bare_metal_server" "itself_bm" {

vpc = var.vpc_id
resource_group = var.resource_group_id
user_data = data.template_file.metadata_startup_script_bm.rendered
user_data = var.bms_boot_drive_encryption == false ? data.template_file.metadata_startup_script_bm.rendered : templatefile("${path.module}/cloud_init.yml", local.user_data_vars)
timeouts {
create = "90m"
}
enable_secure_boot = false
trusted_platform_module {
mode = "tpm_2"
}
}

resource "time_sleep" "wait_for_reboot_tolerate" {
count = var.bms_boot_drive_encryption == true && var.afm_server_type == true && var.total_vsis > 0 ? 1 : 0
create_duration = "400s"
depends_on = [ibm_is_bare_metal_server.itself_bm]
}

resource "null_resource" "scale_boot_drive_reboot_tolerate_provisioner" {
count = var.bms_boot_drive_encryption == true && var.afm_server_type == true && var.total_vsis > 0 ? 1 : 0
connection {
type = "ssh"
host = (tolist([for ip_details in ibm_is_bare_metal_server.itself_bm : ip_details.primary_network_interface[0]["primary_ip"][0]["address"]]))[count.index]
user = "root"
private_key = var.storage_private_key
timeout = "60m"
}

provisioner "remote-exec" {
inline = [
"while true; do",
" lsblk | grep crypt",
" if [[ \"$?\" -eq 0 ]]; then",
" break",
" fi",
" echo \"Waiting for BMS to be rebooted and drive to get encrypted...\"",
" sleep 10",
"done",
"lsblk",
"systemctl restart NetworkManager",
"echo \"Restarted NetworkManager\""
]
}
depends_on = [time_sleep.wait_for_reboot_tolerate]
}

resource "ibm_dns_resource_record" "a_itself_bm" {
Expand Down Expand Up @@ -366,10 +411,10 @@ resource "ibm_dns_resource_record" "ptr_itself_bm" {

output "storage_cluster_instance_name_id_map_vsi_bm" {
value = var.afm_server_type == true ? try({ for instance_details in ibm_is_bare_metal_server.itself_bm : "${instance_details.name}.${var.dns_domain}" => instance_details.id }, {}) : try({ for instance_details in ibm_is_instance.itself : "${instance_details.name}.${var.dns_domain}" => instance_details.id }, {})
depends_on = [ibm_dns_resource_record.a_itself_bm, ibm_dns_resource_record.ptr_itself_bm]
depends_on = [ibm_dns_resource_record.a_itself_vsi, ibm_dns_resource_record.ptr_itself_vsi, ibm_dns_resource_record.a_itself_bm, ibm_dns_resource_record.ptr_itself_bm]
}

output "storage_cluster_instance_name_ip_map_vsi_bm" {
value = var.afm_server_type == true ? try({ for instance_details in ibm_is_bare_metal_server.itself_bm : instance_details.name => instance_details.primary_network_interface[0]["primary_ip"][0]["address"] }, {}) : try({ for instance_details in ibm_is_instance.itself : instance_details.name => instance_details.primary_network_interface[0]["primary_ipv4_address"] }, {})
depends_on = [ibm_dns_resource_record.a_itself_bm, ibm_dns_resource_record.ptr_itself_bm]
depends_on = [ibm_dns_resource_record.a_itself_vsi, ibm_dns_resource_record.ptr_itself_vsi, ibm_dns_resource_record.a_itself_bm, ibm_dns_resource_record.ptr_itself_bm]
}
174 changes: 174 additions & 0 deletions resources/ibmcloud/compute/afm_vsi/cloud_init.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#cloud-config
growpart:
mode: off
devices: ['/']
resize_rootfs: false
write_files:
- content: |
#!/usr/bin/env bash
if grep -q "Red Hat" /etc/os-release
then
USER=vpcuser
PACKAGE_MGR=dnf
if grep -q "platform:el9" /etc/os-release
then
subscription-manager repos --enable=rhel-9-for-x86_64-supplementary-eus-rpms
package_list="python3 kernel-devel-$(uname -r) kernel-headers-$(uname -r) firewalld numactl make gcc-c++ elfutils-libelf-devel bind-utils iptables-nft nfs-utils elfutils elfutils-devel python3-dnf-plugin-versionlock cryptsetup clevis clevis-luks clevis-dracut tpm2-tools"
elif grep -q "platform:el8" /etc/os-release
then
package_list="python38 kernel-devel-$(uname -r) kernel-headers-$(uname -r) firewalld numactl jq make gcc-c++ elfutils-libelf-devel bind-utils iptables nfs-utils elfutils elfutils-devel python3-dnf-plugin-versionlock cryptsetup clevis clevis-luks clevis-dracut tpm2-tools"
fi
RETRY_LIMIT=5
retry_count=0
all_pkg_installed=1
while [[ $all_pkg_installed -ne 0 && $retry_count -lt $RETRY_LIMIT ]]
do
# Install all required packages
echo "INFO: Attempting to install packages"
$PACKAGE_MGR install -y $package_list
# Check to ensure packages are installed
pkg_installed=0
for pkg in $package_list
do
pkg_query=$($PACKAGE_MGR list installed $pkg)
pkg_installed=$(($? + $pkg_installed))
done
if [[ $pkg_installed -ne 0 ]]
then
# The minimum required packages have not been installed.
echo "WARN: Required packages not installed. Sleeping for 60 seconds and retrying..."
touch /var/log/scale-rerun-package-install
echo "INFO: Cleaning and repopulating repository data"
$PACKAGE_MGR clean all
$PACKAGE_MGR makecache
sleep 60
else
all_pkg_installed=0
fi
retry_count=$(( $retry_count+1 ))
done
yum update --security -y
yum versionlock add $package_list
yum versionlock list
echo 'export PATH=$PATH:/usr/lpp/mmfs/bin' >> /root/.bashrc
elif grep -q "Ubuntu" /etc/os-release
then
USER=ubuntu
fi
sed -i -e "s/^/no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command=\"echo \'Please login as the user \\\\\"$USER\\\\\" rather than the user \\\\\"root\\\\\".\';echo;sleep 10; exit 142\" /" ~/.ssh/authorized_keys
echo "${vsi_meta_private_key}" | base64 --decode > /root/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
echo "${vsi_meta_public_key}" | base64 --decode >> /root/.ssh/authorized_keys
echo "StrictHostKeyChecking no" >> ~/.ssh/config
echo "DOMAIN=\"${dns_domain}\"" >> "/etc/sysconfig/network-scripts/ifcfg-eth0"
echo "MTU=9000" >> "/etc/sysconfig/network-scripts/ifcfg-eth0"
sed -i -e "s#QUEUE_COUNT=3#QUEUE_COUNT=\`ethtool -l \$iface | echo \$(awk '\$1 ~ /Combined:/ {print \$2;exit}')\`#g" /var/lib/cloud/scripts/per-boot/iface-config
ethtool -L eth0 combined 16
chage -I -1 -m 0 -M 99999 -E -1 -W 14 vpcuser
systemctl restart NetworkManager
systemctl stop firewalld
firewall-offline-cmd --zone=public --add-port=1191/tcp
firewall-offline-cmd --zone=public --add-port=4444/tcp
firewall-offline-cmd --zone=public --add-port=4444/udp
firewall-offline-cmd --zone=public --add-port=4739/udp
firewall-offline-cmd --zone=public --add-port=4739/tcp
firewall-offline-cmd --zone=public --add-port=9084/tcp
firewall-offline-cmd --zone=public --add-port=9085/tcp
firewall-offline-cmd --zone=public --add-service=http
firewall-offline-cmd --zone=public --add-service=https
firewall-offline-cmd --zone=public --add-port=2049/tcp
firewall-offline-cmd --zone=public --add-port=2049/udp
firewall-offline-cmd --zone=public --add-port=111/tcp
firewall-offline-cmd --zone=public --add-port=111/udp
firewall-offline-cmd --zone=public --add-port=30000-61000/tcp
firewall-offline-cmd --zone=public --add-port=30000-61000/udp
systemctl start firewalld
systemctl enable firewalld
path: /usr/local/bin/scale_user_data.sh
permissions: '0755'
- content: |
#!/bin/bash
# This script encrypts the root partition of a Redhat 8/9 stock IBM Cloud
# image using the TPM to encrypt the LUKS keys. It assumes there is plenty
# of unpartition space on the drive, and leaves the current root partition
# for rescue boot (but this could be deleted on a subsequent boot).
#
# * Create a new partition on the drive using all free space
# * Encrypt the new partition using LUKS with a known passphrase
# * Use 'clevis' to create an additional LUKS passphrase that is bound to the TPM
# * Re-generate initramfs via dracut to ensure the root drive is auto-unlocked on boot
# * Copy the current root filesystem to the new drive
# * Update fstab and crypttab for auto-mounting
# * Update grub to boot using the newly encrypted root drive
#
echo "Encrypt my boot drive"
# Determine the boot device (minus partition name)
# Assumes 'sdaX' or 'nvmeXnYpZ'
device=$(mount | grep "on / type" | awk '{print $1}')
if [[ "$device" =~ "nvme" ]]; then
device=$${device%??}
else
device=$${device%?}
fi
echo $device
# Create a root partition filling up the rest of the drive
echo -e 'n\np\n\n\n\nw' | fdisk $${device}
partition=$(fdisk -l $device | grep $device | tail -1 | awk '{print $1}')
echo $partition
# Setup encryption on the drive with a well known passphrase, and format the filesystem
echo -n n0tsecret | cryptsetup luksFormat --type luks2 -q --force-password $partition
echo -n n0tsecret | cryptsetup open $partition root
mkfs.xfs /dev/mapper/root
# Add the TPM key to the LUKS encrypted drive.
# For additional security, you can bind it to specific TPM PCR banks, but this will cause the TPM unlock
# to fail when the bank changes (EG firmware is updated). If you want to bind it to a PCR:
# ,"pcr_bank":"sha256","pcr_ids":"7"
echo -n n0tsecret | clevis luks bind -y -k - -d $partition tpm2 '{"hash":"sha256","key":"rsa"}'
# Regenerate dracut initramfs to allow unlock on boot
dracut -fv --regenerate-all
# Copy the OS into the encrypted partition
mkdir /mnt/encryptedroot
mount /dev/mapper/root /mnt/encryptedroot
rsync -a --exclude='/proc/*' --exclude='/sys/*' --exclude='/boot' --exclude='/mnt/encryptedroot' / /mnt/encryptedroot
# Grab the UUID for the encrypted partition and setup the crypttab
uuid=$(lsblk -lfi -o NAME,FSTYPE,UUID | grep crypto_LUKS | awk '{print $3}')
echo "root UUID=$${uuid} none luks" > /mnt/encryptedroot/etc/crypttab
# Replace root with '/dev/mapper/root / xfs defaults 0 1' in fstab
sed -i "/\t\/\t/c/dev/mapper/root\t/\txfs\tdefaults\t0\t1" /mnt/encryptedroot/etc/fstab
# Setup grub
# Grab default cmdline args
args=$(grep CMDLINE_LINUX /etc/default/grub | sed 's/.*GRUB_CMDLINE_LINUX=//' | sed 's/\"//g')
# Update grub and set the new entry to be the default.
grubby --add-kernel="/boot/vmlinuz-$(uname -r)" \
--title="Boot from encrypted root" \
--initrd="/boot/initramfs-$(uname -r).img" \
--args "$${args} root=/dev/mapper/root rd.luks.name=$${uuid}=root" \
--make-default
# Since we use EFI, copy the grubenv over (note the \cp is not a typo,
# it ensures that the 'cp' alias isn't used.)
efidir=$(ls /boot/efi/EFI/ | grep -v BOOT)
\cp -f /boot/grub2/grubenv /boot/efi/EFI/$${efidir}/
# We MUST have a separate /boot partiiton to host the kernel and initramfs unencrypted
# as these are needed to unlock the root drive. The IBM CLoud RHEL 9.x images have
# a separate boot partiiton, but 8.x do not.
# If we dont have a separate /boot partition, we'll use the current root partition
# as /boot. So copy the current /boot content into the root of the filessytem.
if ! lsblk -l | grep /boot$; then
rsync -a --exclude='/efi*' /boot/ /
# Current root device UUID - it will become boot device uuid
curr_root_uuid=$(lsblk -fl | grep /$ | awk '{print $4}')
# Add the new /boot partition to fstab for auto-mounting.
echo -e "UUID=$${curr_root_uuid}\t/boot\txfs\tdefaults\t0\t0" >> /mnt/encryptedroot/etc/fstab
fi
# Reboot the system
shutdown -r now
path: /usr/local/bin/boot_drive_encryption.sh
permissions: '0755'
runcmd:
- /usr/local/bin/scale_user_data.sh
- /usr/local/bin/boot_drive_encryption.sh
Loading

0 comments on commit b395801

Please sign in to comment.