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를 참고함.











댓글 없음:

댓글 쓰기

AWS Redis와 Tomcat Session Clustering

근 두달만에 글을 쓰는것 같다 블로그에 글을 올리는게 쉽지 않다는 생각을 해본다. 오늘은 Redis를 이용하여 Tomcat Session Clustering하는 방법을 알아보고자한다. 앞에서 작성했던 AWS DynamoDB를 이용하여 Sessi...