2018년 3월 26일 월요일

AWS VPC에 있는 서버에 접속을 하려면?


외부에서 AWS에 Virtual Private Network(VPC)에 있는 서버에 접속을 하려면 어떻게 해야 할까?

AWS에서는 Public영역에 Bastion Server을 이용하여 점프 할 수 있도록 구성하는것을 권장한다.

아래는 AWS에서 제공하는 Bastion의 Architecture 이다.

Bastion 서버에서 /var/log/bastion/bastion.log에 로그 파일이 있는데 접속된 명령들이 로그로 저장이 된다.이 로그 파일에는 날짜, SSH 클라이언트 연결 IP 주소, 사용자 이름, 작업 디렉터리 및 실행된 명령 등의 정보등이 기록된다.

이 로그에는 사용자 로그인 시 실행된 모든 명령에 대한 기록이 남아 있다. 

아래 그림에는 사용자가 특정 IP 주소를 통해 로그인했으며, 표준 사용자로 암호 파일을 제거하려고 시도한 후 루트 액세스로 에스컬레이션한 다음 접속 로그 제거를 시도했다고 기록된 로그를 보여준다.



bastion.log 파일에는 변경 불가능한 비트 세트가 있어 쉽게 제거하거나 조작할 수 없다고 한다. 악의적 사용자가 bastion.log 파일을 찾아낸 후 루트 권한을 얻어 보호를 해제하고 로그 파일을 삭제하더라도 로그의 사본이 포함된 섀도우 파일이 있다. 
섀도우 파일의 위치는 /var/log/bastion/.bastion.log이다.
이 섀도우 파일은 단순한 사본으로, 공격자가 찾아내 삭제할 수 있어 Cloud Watch Logs서비스를 이용하여 bastion.log파일을 저장하는걸 권장한다.

설치는 아마존에서 제공하는 quick start를 이용하여 배포할수 있다.

AWS설명서를 참고함.

또한 Amazon Linux에 github에 있는 shell을 생성하여 실행시키면 bastion.log가 생성된다.

bootstrap-bastion.sh

#!/bin/bash -x

yum -y update --security

##########################
## ENABLE SSH RECORDING ##
##########################

# Create a new folder for the log files
mkdir /var/log/bastion

# Allow ec2-user only to access this folder and its content
chown ec2-user:ec2-user /var/log/bastion
chmod -R 770 /var/log/bastion
setfacl -Rdm other:0 /var/log/bastion

# Make OpenSSH execute a custom script on logins
echo -e \"\\nForceCommand /usr/bin/bastion/shell\" >> /etc/ssh/sshd_config

# Block some SSH features that bastion host users could use to circumvent the solution
awk '!/AllowTcpForwarding/' /etc/ssh/sshd_config > temp && mv temp /etc/ssh/sshd_config
awk '!/X11Forwarding/' /etc/ssh/sshd_config > temp && mv temp /etc/ssh/sshd_config
echo \"AllowTcpForwarding no\" >> /etc/ssh/sshd_config
echo \"X11Forwarding no\" >> /etc/ssh/sshd_config

mkdir /usr/bin/bastion

cat > /usr/bin/bastion/shell << 'EOF'
# Check that the SSH client did not supply a command
if [[ -z $SSH_ORIGINAL_COMMAND ]]; then
  # The format of log files is /var/log/bastion/YYYY-MM-DD_HH-MM-SS_user
  LOG_FILE=\"`date --date=\"today\" \"+%Y-%m-%d_%H-%M-%S\"`_`whoami`\"
  LOG_DIR=\"/var/log/bastion/\"
  # Print a welcome message
  echo \"\"
  echo \"NOTE: This SSH session will be recorded\"
  echo \"AUDIT KEY: $LOG_FILE\"
  echo \"\"
  # I suffix the log file name with a random string. I explain why later on.
  SUFFIX=`mktemp -u _XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX`
  # Wrap an interactive shell into \"script\" to record the SSH session
  script -qf --timing=$LOG_DIR$LOG_FILE$SUFFIX.time $LOG_DIR$LOG_FILE$SUFFIX.data --command=/bin/bash
else
  # The \"script\" program could be circumvented with some commands (e.g. bash, nc).
  # Therefore, I intentionally prevent users from supplying commands.
  echo \"This bastion supports interactive sessions only. Do not supply a command\"
  exit 1
fi
EOF
# Make the custom script executable
chmod a+x /usr/bin/bastion/shell
# Bastion host users could overwrite and tamper with an existing log file using \"script\" if
# they knew the exact file name. I take several measures to obfuscate the file name:
# 1. Add a random suffix to the log file name.
# 2. Prevent bastion host users from listing the folder containing log files. This is done
#    by changing the group owner of \"script\" and setting GID.
chown root:ec2-user /usr/bin/script
chmod g+s /usr/bin/script
# 3. Prevent bastion host users from viewing processes owned by other users, because the log
#    file name is one of the \"script\" execution parameters.
mount -o remount,rw,hidepid=2 /proc
awk '!/proc/' /etc/fstab > temp && mv temp /etc/fstab
echo \"proc /proc proc defaults,hidepid=2 0 0\" >> /etc/fstab
# Restart the SSH service to apply /etc/ssh/sshd_config modifications.
service sshd restart
############################
## EXPORT LOG FILES TO S3 ##
############################
cat > /usr/bin/bastion/sync_s3 << 'EOF'
# Copy log files to S3 with server-side encryption enabled.
# Then, if successful, delete log files that are older than a day.
LOG_DIR=\"/var/log/bastion/\"
aws s3 cp $LOG_DIR s3://${Bucket}/logs/ --sse --region ${AWS::Region} --recursive && find $LOG_DIR* -mtime +1 -exec rm {} \\;
EOF
chmod 700 /usr/bin/bastion/sync_s3
#######################################
## SYNCHRONIZE USERS AND PUBLIC KEYS ##
#######################################
# Bastion host users should log in to the bastion host with their personal SSH key pair.
# The public keys are stored on S3 with the following naming convention: \"username.pub\".
# This script retrieves the public keys, creates or deletes local user accounts as needed,
# and copies the public key to /home/username/.ssh/authorized_keys
cat > /usr/bin/bastion/sync_users << 'EOF'
# The file will log user changes
LOG_FILE=\"/var/log/bastion/users_changelog.txt\"
# The function returns the user name from the public key file name.
# Example: public-keys/sshuser.pub => sshuser
get_user_name () {
  echo \"$1\" | sed -e 's/.*\\///g' | sed -e 's/\\.pub//g'
}
# For each public key available in the S3 bucket
aws s3api list-objects --bucket ${Bucket} --prefix public-keys/ --region ${AWS::Region} --output text --query 'Contents[?Size>`0`].Key' | sed -e 'y/\\t/\\n/' > ~/keys_retrieved_from_s3
while read line; do
  USER_NAME=\"`get_user_name \"$line\"`\"
  # Make sure the user name is alphanumeric
  if [[ \"$USER_NAME\" =~ ^[a-z][-a-z0-9]*$ ]]; then
    # Create a user account if it does not already exist
    cut -d: -f1 /etc/passwd | grep -qx $USER_NAME
    if [ $? -eq 1 ]; then
      /usr/sbin/adduser $USER_NAME && \\
      mkdir -m 700 /home/$USER_NAME/.ssh && \\
      chown $USER_NAME:$USER_NAME /home/$USER_NAME/.ssh && \\
      echo \"$line\" >> ~/keys_installed && \\
      echo \"`date --date=\"today\" \"+%Y-%m-%d %H-%M-%S\"`: Creating user account for $USER_NAME ($line)\" >> $LOG_FILE
    fi
    # Copy the public key from S3, if an user account was created from this key
    if [ -f ~/keys_installed ]; then
      grep -qx \"$line\" ~/keys_installed
      if [ $? -eq 0 ]; then
        aws s3 cp s3://${Bucket}/$line /home/$USER_NAME/.ssh/authorized_keys --region ${AWS::Region}
        chmod 600 /home/$USER_NAME/.ssh/authorized_keys
        chown $USER_NAME:$USER_NAME /home/$USER_NAME/.ssh/authorized_keys
      fi
    fi
  fi
done < ~/keys_retrieved_from_s3
# Remove user accounts whose public key was deleted from S3
if [ -f ~/keys_installed ]; then
  sort -uo ~/keys_installed ~/keys_installed
  sort -uo ~/keys_retrieved_from_s3 ~/keys_retrieved_from_s3
  comm -13 ~/keys_retrieved_from_s3 ~/keys_installed | sed \"s/\\t//g\" > ~/keys_to_remove
  while read line; do
    USER_NAME=\"`get_user_name \"$line\"`\"
    echo \"`date --date=\"today\" \"+%Y-%m-%d %H-%M-%S\"`: Removing user account for $USER_NAME ($line)\" >> $LOG_FILE
    /usr/sbin/userdel -r -f $USER_NAME
  done < ~/keys_to_remove
  comm -3 ~/keys_installed ~/keys_to_remove | sed \"s/\\t//g\" > ~/tmp && mv ~/tmp ~/keys_installed
fi
EOF
chmod 700 /usr/bin/bastion/sync_users
###########################################
## SCHEDULE SCRIPTS AND SECURITY UPDATES ##
###########################################
cat > ~/mycron << EOF
*/5 * * * * /usr/bin/bastion/sync_s3
*/5 * * * * /usr/bin/bastion/sync_users
0 0 * * * yum -y update --security
EOF
crontab ~/mycron
rm ~/mycron
/opt/aws/bin/cfn-signal -e 0 --stack ${AWS::StackName} --resource BastionHostInstance --region ${AWS::Region}

위 소스는 아래 github를 참고함.











댓글 없음:

댓글 쓰기

EBS 볼륨 확장 정리: 수동 확장부터 자동 확장, 모니터링까지 (Linux 기준)

  Amazon Web Services 에서 EC2 인스턴스를 운영하다 보면 EBS 볼륨 용량을 늘려야 하는 상황은 자주 발생합니다.  하지만 EBS 볼륨 크기를 늘렸다고 해서 파일 시스템이 자동으로 확장되지는 않습니다. 볼륨 확장 이후에는 파일 ...