diff --git a/init b/init index ff9845c..20c3b6b 100755 --- a/init +++ b/init @@ -12,8 +12,8 @@ else VERSION="$1" fi -# Control tier - must form an etcd2 cluster first -if [ "$NODE_ROLE" = "control" ]; then +# Control and Bastion tiers - must form an etcd2 cluster first +if [ "$NODE_ROLE" = "control" ] || [ "$NODE_ROLE" = "bastion" ]; then sudo ${SCRIPTDIR}/$VERSION/util/etcd2-setup.sh $SCRIPTDIR fi if [ "$NODE_ROLE" = "it-hybrid" ]; then @@ -49,6 +49,9 @@ ${SCRIPTDIR}/$VERSION/util/seed-etcd.sh || : # The mesos-credentials.sh script must run after seed-etcd.sh sudo ${SCRIPTDIR}/$VERSION/util/mesos-credentials.sh || : +# The klam-ssh.sh script must run after seed-etcd.sh +sudo ${SCRIPTDIR}/$VERSION/util/klam-ssh.sh || : + etcdctl get /environment/SCRIPTS-FORK if [[ $? = 4 ]]; then # 4 == 404 - key not found diff --git a/v3/profile.d/bastion/etcdctl.sh b/v3/profile.d/bastion/etcdctl.sh new file mode 120000 index 0000000..5699a39 --- /dev/null +++ b/v3/profile.d/bastion/etcdctl.sh @@ -0,0 +1 @@ +../common/etcdctl.sh \ No newline at end of file diff --git a/v3/profile.d/bastion/fleetctl.sh b/v3/profile.d/bastion/fleetctl.sh new file mode 120000 index 0000000..e2027d1 --- /dev/null +++ b/v3/profile.d/bastion/fleetctl.sh @@ -0,0 +1 @@ +../common/fleetctl.sh \ No newline at end of file diff --git a/v3/profile.d/profile.sh b/v3/profile.d/profile.sh index 3f2931d..f008ff6 100644 --- a/v3/profile.d/profile.sh +++ b/v3/profile.d/profile.sh @@ -9,5 +9,5 @@ fi # set the prompt for non-root users if [[ ${EUID} != 0 ]]; then source /etc/environment - export PS1="\[\\033[01;32m\]\u@\h\[\\033[01;34m\] \[\\033[01;30m\]$NODE_TIER-$NODE_PRODUCT-$ZONE-$NODE_ROLE \[\\033[01;34m\]\w \$\[\\033[00m\] " + export PS1="\[\\033[01;32m\]$(who -m | awk '{print $1}')@\h\[\\033[01;34m\] \[\\033[01;30m\]$NODE_TIER-$NODE_PRODUCT-$ZONE-$NODE_ROLE \[\\033[01;34m\]\w \$\[\\033[00m\] " fi diff --git a/v3/util/authorizedkeys_command.sh b/v3/util/authorizedkeys_command.sh new file mode 100755 index 0000000..51cc7d2 --- /dev/null +++ b/v3/util/authorizedkeys_command.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +ROLE_NAME="$(etcdctl get /klam-ssh/config/role-name)" +ENCRYPTION_ID="$(etcdctl get /klam-ssh/config/encryption-id)" +ENCRYPTION_KEY="$(etcdctl get /klam-ssh/config/encryption-key)" +KEY_LOCATION_PREFIX="$(etcdctl get /klam-ssh/config/key-location-prefix)" +IMAGE="$(etcdctl get /images/klam-ssh)" + +echo "Running authorizedkeys_command for $1" | systemd-cat -p info -t klam-ssh + +docker run --rm -e ROLE_NAME=${ROLE_NAME} -e ENCRYPTION_ID=${ENCRYPTION_ID} -e ENCRYPTION_KEY=${ENCRYPTION_KEY} -e KEY_LOCATION_PREFIX=${KEY_LOCATION_PREFIX} ${IMAGE} /usr/lib/klam/getKeys.py $1 +exit 0 diff --git a/v3/util/downloadS3.sh b/v3/util/downloadS3.sh new file mode 100755 index 0000000..816a715 --- /dev/null +++ b/v3/util/downloadS3.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +ROLE_NAME="$(etcdctl get /klam-ssh/config/role-name)" +ENCRYPTION_ID="$(etcdctl get /klam-ssh/config/encryption-id)" +ENCRYPTION_KEY="$(etcdctl get /klam-ssh/config/encryption-key)" +KEY_LOCATION_PREFIX="$(etcdctl get /klam-ssh/config/key-location-prefix)" +IMAGE="$(etcdctl get /images/klam-ssh)" + +docker run --rm -e ROLE_NAME=${ROLE_NAME} -e ENCRYPTION_ID=${ENCRYPTION_ID} -e ENCRYPTION_KEY=${ENCRYPTION_KEY} -e KEY_LOCATION_PREFIX=${KEY_LOCATION_PREFIX} ${IMAGE} /usr/lib/klam/downloadS3.py +exit 0 diff --git a/v3/util/klam-ssh.sh b/v3/util/klam-ssh.sh new file mode 100755 index 0000000..5c33a75 --- /dev/null +++ b/v3/util/klam-ssh.sh @@ -0,0 +1,144 @@ +#!/bin/bash -xe + +etcdctl set /images/klam-ssh "adobecloudops/klam-ssh:latest" + +AZ=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone) +REGION=${AZ::-1} +ROLE_NAME="$(etcdctl get /klam-ssh/config/role-name)" +ENCRYPTION_ID="$(etcdctl get /klam-ssh/config/encryption-id)" +ENCRYPTION_KEY="$(etcdctl get /klam-ssh/config/encryption-key)" +KEY_LOCATION_PREFIX="$(etcdctl get /klam-ssh/config/key-location-prefix)" +IMAGE="$(etcdctl get /images/klam-ssh)" + + +case $REGION in + "eu-west-1") + KEY_LOCATION="-ew1" ;; + "ap-northeast-1") + KEY_LOCATION="-an1" ;; + "us-east-1") + KEY_LOCATION="-ue1" ;; + "us-west-1") + KEY_LOCATION="-uw1" ;; + "us-west-2") + KEY_LOCATION="-uw2" ;; + *) + echo "An incorrect region value specified" + exit 1 + ;; +esac + +# create nsswitch.conf +cat << EOT >> /home/core/nsswitch.conf +passwd: files usrfiles ato +shadow: files usrfiles ato +group: files usrfiles ato + +hosts: files usrfiles dns +networks: files usrfiles dns + +services: files usrfiles +protocols: files usrfiles +rpc: files usrfiles + +ethers: files +netmasks: files +netgroup: nisplus +bootparams: files +automount: files nisplus +aliases: files nisplus +EOT + +# create klam-ssh.conf +cat << EOT >> /home/core/klam-ssh.conf +{ + key_location: ${KEY_LOCATION_PREFIX}${KEY_LOCATION}, + role_name: ${ROLE_NAME}, + encryption_id: ${ENCRYPTION_ID}, + encryption_key: ${ENCRYPTION_KEY}, + resource_location: amazon, + time_skew: permissive, + s3_region: ${REGION} +} +EOT + +# Create directory structure +mkdir -p /opt/klam/lib /opt/klam/lib64 /etc/ld.so.conf.d + +# Docker volume mount +docker create --name klam-ssh ${IMAGE} + +# Copy libnss_ato library +docker cp klam-ssh:/tmp/klam-build/coreos/libnss_ato.so.2 /opt/klam/lib64 + +# Create symlink +ln -sf /opt/klam/lib64/libnss_ato.so.2 /opt/klam/lib64/libnss_ato.so + +# Docker remove container +docker rm klam-ssh + +# Move the ld.so.conf file to the correct location +echo "/opt/klam/lib64" > /etc/ld.so.conf.d/klam.conf +ldconfig +ldconfig -p | grep klam + +# Validate that the files exist in the correct folder +ls -l /opt/klam/lib64/libnss_ato.so* + +# Create the klamfed home directory +useradd -p "*" -U -G sudo -u 5000 -m klamfed -s /bin/bash +mkdir -p /home/klamfed +usermod -p "*" klamfed +usermod -U klamfed +update-ssh-keys -u klamfed || : + +# Add klamfed to wheel +usermod -a -G wheel klamfed + +# Add klamfed to sudo +usermod -a -G sudo klamfed + +# Add passwordless sudo to klamfed +echo "klamfed ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/klamfed + +# Validate that the klamfed user has the correct uid value (5000) and home directory +id klamfed +ls -ld /home/klamfed + +# Re-link nsswitch.conf +mv -f /home/core/nsswitch.conf /etc/nsswitch.conf +cat /etc/nsswitch.conf + +# generate the ATO config +grep klamfed /etc/passwd > /opt/klam/lib/klam-ato.conf + +# Validate that the contents of /opt/klam/lib/klam-ato.conf +cat /opt/klam/lib/klam-ato.conf + +# Move klam-ssh.conf +mv -f /home/core/klam-ssh.conf /opt/klam/lib/klam-ssh.conf +cat /opt/klam/lib/klam-ssh.conf + +# update /etc/ssh/sshd_config +cp /etc/ssh/sshd_config sshd_config +echo 'AuthorizedKeysCommand /opt/klam/lib/authorizedkeys_command.sh' >> sshd_config +echo 'AuthorizedKeysCommandUser root' >> sshd_config +mv -f sshd_config /etc/ssh/sshd_config +cat /etc/ssh/sshd_config + +# Change ownership of authorizedkeys_command +chown root:root /home/core/mesos-systemd/v3/util/authorizedkeys_command.sh + +# Relocate authorizedkeys_command +mv /home/core/mesos-systemd/v3/util/authorizedkeys_command.sh /opt/klam/lib + +# Change ownership of downloadS3 +chown root:root /home/core/mesos-systemd/v3/util/downloadS3.sh + +# Relocate downloadS3.sh +mv /home/core/mesos-systemd/v3/util/downloadS3.sh /opt/klam/lib + +# Restart SSHD +systemctl restart sshd.service + +echo "KLAM SSH BOOTSTRAP COMPLETE" diff --git a/v3/util/ssh-client-config.sh b/v3/util/ssh-client-config.sh new file mode 100755 index 0000000..e512f80 --- /dev/null +++ b/v3/util/ssh-client-config.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Use meta-data to determine the public IPv4 of this bastion host and the vpc's cidr block +IP=$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4) +ETH0_MAC=$(ifconfig eth0 | grep ether | awk '{print tolower($2)}') +VPC_CIDR=$(curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/${ETH0_MAC}/vpc-ipv4-cidr-block) + +# Split the network IP from the mask and assign them to separate variables +IFS='/' read -r -a CIDR_ARRAY <<< "${VPC_CIDR}" +NETWORK=${CIDR_ARRAY[0]} +MASK=${CIDR_ARRAY[1]} + +# Determine how many /24 networks fit into the given VPC_CIDR. Yes, this is ugly for two reasons. +# One, ssh_config only allows string pattern matching, so for subnets, one can only use a network +# terminated with a wildcard for the last octet. Second, there's a limit to the size of the VPC +# that can be allocated in Adobe private address space. HamCIDR only allows CIDR blocks from /25 +# to /22, so any other value is bypassing SOP. A case statement can't do range comparisons, and +# I didn't want to implement a subnet calculator in BASH, so there's this: + +if [[ "${MASK}" -ge 24 ]]; then SUBNETS=1 +elif [[ "${MASK}" == 23 ]]; then SUBNETS=2 +elif [[ "${MASK}" == 22 ]]; then SUBNETS=4 +elif [[ "${MASK}" == 21 ]]; then SUBNETS=8 +elif [[ "${MASK}" == 20 ]]; then SUBNETS=16 +else + echo "Your large CIDR block broke teh internets." + exit 1 +fi + +# Build the string of /24 networks to use in the ssh_config +HOSTS=$(for ((i = 0; i < ${SUBNETS}; i++)); do echo ${NETWORK} | awk -v x="${i}" -F. '{printf "%d.%d.%d.%s", $1,$2,$3+x,"* "}'; done; echo) + + +cat << EOF +Host ${IP} + ForwardAgent yes + IdentityFile ~/.ssh/ssh.pem + +Host ${HOSTS} + IdentityFile ~/.ssh/ssh.pem + ProxyCommand ssh ${IP} ncat %h %p +EOF