金山云云服务器访问控制和操作审计
公有云给用户不仅仅带来弹性和按量计费的资源,也提供了在任何地方操作和使用资源的灵活性。但是,为了保证用户在云上环境的安全性,避免环境管理混乱,需要对云资源的操作和访问进行严格的访问控制和操作审计。
为了达到这一目标,用户可以采用专业的堡垒机软件,也可以通过利用Linux操作系统,并结合云网络的特性来实现。本文介绍如何利用金山云的云网络能力,并通过配置Linux系统来实现堡垒机功能,提高对金山云云服务器的访问控制和操作审计,并实现如下需求:
- 只有堡垒机具有公网IP,其他云服务器不能具有公网IP;
- 所有云服务器操作必须先登录到堡垒机,然后通过堡垒机再SSH到其他云服务器,而且不能从一台应用服务器SSH到另外一台应用服务器;
- 所有用户登录堡垒机必须采用密钥登录,不能采用口令登录;
- 非root用户登录到堡垒机后,只能查看该用户到进程信息,不能查看其他用户的进程信息;
- 所有在堡垒机上执行的shell命令将被记录用于后期审计;
- 应用服务器能访问Linux yum源和金山云短信服务:https://ksms.api.ksyun.com,但不能访问其他服务;
- 应用服务器提供的Web服务只能通过负载均衡提供的弹性IP访问。
本方案的整体架构描述如下图:
本文包含如下内容:
- 网络规划;
- 准备云服务器;
- 配置堡垒机;
- 配置应用服务器;
- 验证访问控制和审计。
1 网络规划
本指南所使用的环境位于金山云北京6区。
1.1 VPC配置
网络资源 | 名称 | CIDR |
---|---|---|
VPC | sbt-vpc | 10.34.0.0/16 |
1.2 子网配置
子网名称 | 所属VPC | 可用区 | 子网类型 | CIDR | 说明 |
---|---|---|---|---|---|
public_a | sbt-vpc | 可用区A | 普通子网 | 10.34.51.0/24 | 用于堡垒机 |
private_a | sbt-vpc | 可用区A | 普通子网 | 10.34.0.0/20 | 用于云服务器 |
1.3 安全组配置
需要注意到是,同安全组下的服务器是直接互通的,无需进行相关设置。
作为实验环境,创建安全组sg-bastion和sg-app,其中绑定sg-bastion的云服务器可以被外网ping通,以及通过ssh访问。sg-bastion的入站规则如下:
协议 | 行为 | 起始端口 | 结束端口 | 源IP |
---|---|---|---|---|
ICMP | 允许 | 全部协议 | 全部协议 | 0.0.0.0/0 |
TCP | 允许 | 22 | 22 | 0.0.0.0/0 |
sg-bastion的出站规则采用如下默认设置:
协议 | 行为 | 起始端口 | 结束端口 | 源IP |
---|---|---|---|---|
IP | 允许 | - | - | 0.0.0.0/0 |
TCP | 允许 | 22 | 22 | 0.0.0.0/0 |
安全组sg-app将绑定到应用服务器上。应用服务器可以被外部访问80端口(提供HTTP服务),并可接受来自于堡垒机(堡垒机的内部IP为10.34.32.21)的SSH请求,同时也可以被其他云服务器ping通。因此,sg-app的入站规则如下:
协议 | 行为 | 起始端口 | 结束端口 | 源IP |
---|---|---|---|---|
ICMP | 允许 | 全部协议 | 全部协议 | 0.0.0.0/0 |
TCP | 允许 | 22 | 22 | 110.34.32.21/32 |
HTTP | 允许 | 80 | 80 | 0.0.0.0/0 |
安全组sg-app的出站规则采用和sg-bastion相同出站规则。
1.3 网络ACL配置
需要注意的是,同一个子网内的主机不受关联的ACL策略控制,因此不能通过网络ACL配置,限制同一子网的云服务器之间相互SSH登录。
应用服务器不能被外网访问,但可以通过公网NAT访问外网服务(120.92.15.230是金山云短信服务域名ksms.api.ksyun.com的IP地址)。为了限制所能访问的外网服务,将为应用服务器所在的私有子网private_a(10.34.0.0/20)绑定一个网络ACL。该网络ACL的入站规则配置如下:
优先级 | 协议 | 行为 | 起始端口 | 结束端口 | 目标IP | 备注 |
---|---|---|---|---|---|---|
100 | IP | 允许 | - | - | 0.0.0.0/0 | 可接受任意包 |
出站规则配置如下:
优先级 | 协议 | 行为 | 起始端口 | 结束端口 | 目标IP | 备注 |
---|---|---|---|---|---|---|
100 | IP | 允许 | - | - | 10.34.0.0/16 | 可访问VPC中的任意服务 |
200 | UDP | 允许 | 53 | 53 | 0.0.0.0/0 | DNS服务 |
210 | ICMP | 允许 | 全部协议 | 全部协议 | 0.0.0.0/0 | ping |
300 | TCP | 允许 | 80 | 80 | 219.216.128.25/32 | neusoft大学yum源 |
310 | TCP | 允许 | 80 | 80 | 198.18.254.30/32 | 金山云yum源 |
320 | TCP | 允许 | 80 | 80 | 216.176.179.218/32 | mirrorlist-centos-org |
400 | TCP | 允许 | 443 | 443 | 120.92.15.230/32 | 金山云短信服务 |
500 | IP | 拒绝 | - | - | 0.0.0.0/0 | 拒绝其他服务 |
1.4 NAT配置信息
为了私有云子网的云服务器能访问外网服务(比如金山云短信服务),因此需要配置公网NAT实例。下面是NAT实例的配置信息。
名称 | 所属VPC | 作用范围 | 类型 | 所绑定的子网 |
---|---|---|---|---|
Ksc_Nat | sbt-vpc | 绑定的子网 | 公网 | private_a |
1.5 负载均衡配置
负载均衡名称 | IP版本 | 状态 | 网络类型 | 所属项目 | VPC实例名 | 弹性IP |
---|---|---|---|---|---|---|
ymq-slb001 | IPv4 | 开启 | 公网 | SBT | sbt-vpc | 120.131.1.39 |
在该负载均衡实例下创建侦听器。此外,如果需要限制某些客户端访问,可以通过绑定ACL,实现对某些IP地址的封禁。
下面是用于绑定到负载均衡实例侦听器上的网络ACL acl-slb,当前配置的规则是不限制任何访问IP。acl-slb的入站规则如下(负载均衡服务下创建的访问控制ACL无需定义出站规则)。
优先级 | 协议 | 行为 | 起始端口 | 结束端口 | 目标IP | 备注 |
---|---|---|---|---|---|---|
100 | IP | 允许 | - | - | 0.0.0.0/0 | 可接受任意包 |
2 准备云服务器
金山云的云服务器可以非为全云盘(系统盘和数据盘都是云硬盘)和非全云盘两大类。全云盘服务器提供了更好的SLA,而非全云盘服务器可以充分利用本地盘的磁盘能力。
为了提高堡垒机的可用性,建议采用全云盘服务器。此外,该服务器将绑定一个弹性IP。为了避免被云服务器SSH账户密码被暴力破解,禁用口令登录,而采用SSH密钥登录。下面是堡垒机云服务器的配置信息
名称 | 类型 | 所属于VPC | 所属子网 | 配置 | IPV4地址 | 安全组 | 操作系统 | 登录方式 | 弹性IP |
---|---|---|---|---|---|---|---|---|---|
ymq-bastion | 通用型N3 | sbt-vpc | public_a | 2核8G | 10.34.32.21 | sg-bastion | CentOS Linux release 7.7.1908 (Core) | SSH Kkey | 120.92.42.167 |
应用服务器位于私有子网,可提供口令登录。下面是一台应用服务器的配置。
名称 | 类型 | 所属于VPC | 所属子网 | 配置 | IPV4地址 | 安全组 | 操作系统 | 登录方式 |
---|---|---|---|---|---|---|---|---|
ymq-srv-1 | 通用型N3 | sbt-vpc | private_a | 8核32G | 10.32.0.2 | sg-app | CentOS Linux release 7.7.1908 (Core) | 密码 |
为了对内网IP进行有序管理,建议在创建云服务器时选择手工指定IP,而不选择系统自动分配。
3 配置堡垒机
3.1 配置SSHD配置文件
通过修改配置文件,显示SSH登录后显示的提示,并记录所执行的shell命令,便于后期操作审计。
在创建堡垒机云服务器后,系统信息如下:
[root@ymq-bastion ~]# cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
从github上获得堡垒机配置脚本。
wget https://raw.githubusercontent.com/ksc-sbt/bastion/master/bastion_bootstrap.sh
然后修改脚本的执行权限:
chmod +x bastion_bootstrap.sh
然后运行SSHD配置脚本bastion_bootstrap.sh。
[root@ymq-bastion ~]# ./bastion_bootstrap.sh
checkos Ended
verify_dependencies Ended
Setting up bastion session log in /var/log/bastion/bastion.log
BANNER_PATH = https://raw.githubusercontent.com/ksc-sbt/bastion/master/ssh-banner.txt
Creating Banner in /etc/ssh_banner
curl -s https://raw.githubusercontent.com/ksc-sbt/bastion/master/ssh-banner.txt > /etc/ssh_banner
[INFO] Installing banner ...
setup_os Started
setup_os Ended
setup_logs Started
prevent_process_snooping Ended
Bootstrap complete.
[root@ymq-bastion ~]# vi /etc/ssh
ssh/ ssh_banner
[root@ymq-bastion ~]# vi /etc/ssh/sshd_config
在重新登录后,将显示如下界面。
michaeldembp-2:~ myang$ ssh -i key/ksyun/ymq-ksyun.pem root@120.92.115.21
###############################################################################
# _ ___ __ _ _____ _ _ #
# | |/ (_) / _| | / ____| | | | #
# | ' / _ _ __ __ _ ___ ___ | |_| |_ | | | | ___ _ _ __| | #
# | < | | '_ \ / _` / __|/ _ \| _| __| | | | |/ _ \| | | |/ _` | #
# | . \| | | | | (_| \__ \ (_) | | | |_ | |____| | (_) | |_| | (_| | #
# |_|\_\_|_| |_|\__, |___/\___/|_| \__| \_____|_|\___/ \__,_|\__,_| #
# __/ | #
# |___/ #
#-----------------------------------------------------------------------------#
# Authorized access only! #
# Disconnect IMMEDIATELY if you are not an authorized user!!! #
# All actions will be monitored and recorded. #
###############################################################################
Last login: Sat Oct 12 17:35:39 2019 from 114.255.44.139
此外,通过查看/var/log/bastion/bastion.log,能看到操作信息。
[root@ymq-bastion ~]# tail -f /var/log/bastion/bastion.log
[ON]:Mon Oct 14 10:25:49 CST 2019 [FROM]:114.255.44.141 [USER]:root [PWD]:/root: ssh 10.34.0.3
[ON]:Mon Oct 14 10:26:21 CST 2019 [FROM]:114.255.44.141 [USER]:root [PWD]:/root: vi /var/log/bastion/bastion.log
3.2 配置堡垒机普通用户(user001),并只允许密钥登录
创建user001用户.
[root@ymq-bastion /]# useradd user001
[root@ymq-bastion /]# id user001
uid=1000(user001) gid=1000(user001) groups=1000(user001)
root用户切换到user001用户,并执行ssh-keygen命令生成密钥。
[root@ymq-bastion /]# su - user001
[user001@ymq-bastion ~]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user001/.ssh/id_rsa):
Created directory '/home/user001/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user001/.ssh/id_rsa.
Your public key has been saved in /home/user001/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:+wqNDAm5J7z+GGr5ipENVBHjh3tRG7BeMvq5be5eARQ user001@ymq-bastion.ksc.com
The key's randomart image is:
+---[RSA 2048]----+
| =o..E. |
| o.o + o |
| .oo * + |
|.. o=.= . |
|. +o+o S. |
| + +oo.o .. |
|o = o+ o. |
|.* o oo.. |
|+.=o..==... |
+----[SHA256]-----+
[user001@ymq-bastion ~]$ ls .ssh
id_rsa id_rsa.pub
密钥生成后会在.ssh目录下创建两个文件,id_rsa和id_rsa.pub,其中id_rsa是私钥,id_rsa.pub这个是公钥。
在.ssh目录下形成authorized_keys文件。
[user001@ymq-bastion ~]$ cd .ssh
[user001@ymq-bastion .ssh]$ cp id_rsa.pub authorized_keys
[user001@ymq-bastion .ssh]$ chmod 600 authorized_keys
[user001@ymq-bastion .ssh]$
系统管理员然后把目录下id_rsa文件发送给user001账号对应的用户,并修改文件的访问模式为400。
MichaeldeMacBook-Pro-2:ksyun myang$ chmod 400 user001_id_rsa01
MichaeldeMacBook-Pro-2:ksyun myang$ ls -al user001_id_rsa01
-r-------- 1 myang staff 1675 Oct 14 11:17 user001_id_rsa01
下面用户就可以用user001账号登录堡垒机了。
MichaeldeMacBook-Pro-2:~ myang$ ssh -i key/ksyun/user001_id_rsa01 user001@120.92.115.21
###############################################################################
# _ ___ __ _ _____ _ _ #
# | |/ (_) / _| | / ____| | | | #
# | ' / _ _ __ __ _ ___ ___ | |_| |_ | | | | ___ _ _ __| | #
# | < | | '_ \ / _` / __|/ _ \| _| __| | | | |/ _ \| | | |/ _` | #
# | . \| | | | | (_| \__ \ (_) | | | |_ | |____| | (_) | |_| | (_| | #
# |_|\_\_|_| |_|\__, |___/\___/|_| \__| \_____|_|\___/ \__,_|\__,_| #
# __/ | #
# |___/ #
#-----------------------------------------------------------------------------#
# Authorized access only! #
# Disconnect IMMEDIATELY if you are not an authorized user!!! #
# All actions will be monitored and recorded. #
###############################################################################
Last login: Mon Oct 14 10:33:29 2019
[user001@ymq-bastion ~]$ id
uid=1000(user001) gid=1000(user001) groups=1000(user001)
[user001@ymq-bastion ~]$
4 配置应用服务器
为了对所有的ssh登录行为进行审计,应用服务器只允许通过堡垒机进行ssh登录。
修改/etc/hosts.allow,允许从堡垒机(10.34.32.21)上登录。
[root@srv001 ~]# cat /etc/hosts.allow
#
# hosts.allow This file contains access rules which are used to
# allow or deny connections to network services that
# either use the tcp_wrappers library or that have been
# started through a tcp_wrappers-enabled xinetd.
#
# See 'man 5 hosts_options' and 'man 5 hosts_access'
# for information on rule syntax.
# See 'man tcpd' for information on tcp_wrappers
#
sshd:10.34.32.21:allow
修改/etc/hosts.deny,禁止所有服务器ssh登录。
[root@srv001 ~]# cat /etc/hosts.deny
#
# hosts.deny This file contains access rules which are used to
# deny connections to network services that either use
# the tcp_wrappers library or that have been
# started through a tcp_wrappers-enabled xinetd.
#
# The rules in this file can also be set up in
# /etc/hosts.allow with a 'deny' option instead.
#
# See 'man 5 hosts_options' and 'man 5 hosts_access'
# for information on rule syntax.
# See 'man tcpd' for information on tcp_wrappers
#
sshd:ALL
然后重新启动sshd服务。
systemctl restart sshd
此时再次从非堡垒机ssh登录,将出现如下提示信息。
[root@ymq-bastion /]# ssh 10.34.0.3
root@10.34.0.3's password:
Last login: Mon Oct 14 10:08:55 2019 from 10.34.32.21
[root@srv002 ~]# ssh 10.34.0.2
ssh_exchange_identification: read: Connection reset by peer
5 验证访问控制和审计
5.1 只有堡垒机具有公网IP,其他云服务器不能具有公网IP
该功能通过金山云控制台给堡垒机绑定公网IP。如果用户采用金山云访问控制(IAM)服务设置多用户,需要严格控制非系统管理账户的弹性IP创建和修改权限。
5.2 SSH登录限制
所有云服务器操作必须先登录到堡垒机,然后通过堡垒机再SSH到其他云服务器,而且不能从一台应用服务器SSH到另外一台应用服务器。
下面验证能通过堡垒机ssh一台云服务器(10.34.0.3),但不能从该云云服务器(10.34.0.3)ssh到另外一台云服务器(10.34.0.2)。
[root@ymq-bastion ~]# ssh 10.34.0.3
root@10.34.0.3's password:
Last login: Mon Oct 14 11:57:33 2019 from 10.34.32.21
[root@srv002 ~]# ssh 10.34.0.2
ssh_exchange_identification: read: Connection reset by peer
[root@srv002 ~]#
5.3 所有用户登录堡垒机必须采用密钥登录,不能采用口令登录
下面验证如果不带密钥ssh,将提示登录失败。
michaeldembp-2:~ myang$ ssh user001@120.92.115.21
###############################################################################
# _ ___ __ _ _____ _ _ #
# | |/ (_) / _| | / ____| | | | #
# | ' / _ _ __ __ _ ___ ___ | |_| |_ | | | | ___ _ _ __| | #
# | < | | '_ \ / _` / __|/ _ \| _| __| | | | |/ _ \| | | |/ _` | #
# | . \| | | | | (_| \__ \ (_) | | | |_ | |____| | (_) | |_| | (_| | #
# |_|\_\_|_| |_|\__, |___/\___/|_| \__| \_____|_|\___/ \__,_|\__,_| #
# __/ | #
# |___/ #
#-----------------------------------------------------------------------------#
# Authorized access only! #
# Disconnect IMMEDIATELY if you are not an authorized user!!! #
# All actions will be monitored and recorded. #
###############################################################################
user001@120.92.115.21: Permission denied (publickey).
michaeldembp-2:~ myang$
5.4 非root用户登录到堡垒机后,只能查看该用户到进程信息,不能查看其他用户的进程信息。
[user001@vm10-34-32-21 ~]$ ps -ef
UID PID PPID C STIME TTY TIME CMD
user001 7702 7701 0 11:23 pts/1 00:00:00 -bash
user001 9329 7702 0 12:03 pts/1 00:00:00 -bash
user001 9332 9329 0 12:03 pts/1 00:00:00 logger -t [ON]:Mon Oct 14 12:03:45 CST 2019 [FROM]:114.255.44.14
user001 10464 10463 0 12:35 pts/3 00:00:00 -bash
user001 10493 10464 0 12:35 pts/3 00:00:00 -bash
user001 10496 10493 0 12:35 pts/3 00:00:00 logger -t [ON]:Mon Oct 14 12:35:16 CST 2019 [FROM]:114.255.44.14
user001 10497 10464 0 12:35 pts/3 00:00:00 ps -ef
5.5 所有在堡垒机上执行的shell命令将被记录用于后期审计
下面是通过root用户查看操作日志文件/var/log/bastion/bastion.log 看到的信息。
[root@vm10-34-32-21 ~]# tail -f /var/log/bastion/bastion.log
[ON]:Mon Oct 14 11:48:14 CST 2019 [FROM]:114.255.44.141 [USER]:root [PWD]:/: ifconfig
[ON]:Mon Oct 14 12:00:22 CST 2019 [FROM]:114.255.44.141 [USER]:user001 [PWD]:/home/user001: ssh root@10.34.0.2
[ON]:Mon Oct 14 12:00:28 CST 2019 [FROM]:114.255.44.141 [USER]:user001 [PWD]:/home/user001: curl 120.131.1.39
[ON]:Mon Oct 14 12:02:34 CST 2019 [FROM]:114.255.44.141 [USER]:user001 [PWD]:/home/user001: ping 120.131.1.39
[ON]:Mon Oct 14 12:03:11 CST 2019 [FROM]:114.255.44.141 [USER]:user001 [PWD]:/home/user001: curl 120.131.1.39
[ON]:Mon Oct 14 12:03:20 CST 2019 [FROM]:114.255.44.141 [USER]:root [PWD]:/root: service firewalld status
[ON]:Mon Oct 14 12:08:51 CST 2019 [FROM]:114.255.44.141 [USER]:root [PWD]:/root: ssh 10.34.0.3
[ON]:Mon Oct 14 12:35:03 CST 2019 [FROM]:114.255.44.141 [USER]:root [PWD]:/root: ssh 10.34.0.2
[ON]:Mon Oct 14 12:35:19 CST 2019 [FROM]:114.255.44.141 [USER]:user001 [PWD]:/home/user001: ps -ef
[ON]:Mon Oct 14 12:35:48 CST 2019 [FROM]:114.255.44.141 [USER]:user001 [PWD]:/home/user001: tail -f /var/log/bastion/bastion.log
5.6 应用服务器能访问Linux yum源和金山云短信服务,但不能访问其他服务
应用服务器能访问yum源服务和金山云短信服务,但不能访问其他服务(比如baidu.com)。
[root@srv001 ~]# curl mirrors.neusoft.edu.cn -I
HTTP/1.1 200 OK
Date: Mon, 14 Oct 2019 04:45:24 GMT
Content-Type: text/html; charset=utf-8
Connection: close
Server: nginx/1.16.1
X-Frame-Options: DENY
[root@srv001 ~]# curl https://ksms.api.ksyun.com -I
HTTP/1.1 400 Bad Request
Date: Mon, 14 Oct 2019 04:38:17 GMT
Content-Type: application/xml
Connection: keep-alive
Server: ksyun-open-platform
[root@srv001 ~]# curl baidu.com -I
^C
5.7 应用服务器提供的Web服务只能通过负载均衡提供的弹性IP访问
MichaeldeMacBook-Pro-2:~ myang$ curl 120.131.1.39
Master
6 总结
本文总结了如何在金山云上自建堡垒机,并结合网络访问控制功能,提升金山云云服务器环境的访问控制和审计。通过金山云控制台的访问控制和操作审计分别是通过“访问控制”和“操作审计”服务实现。
7 参考资料
-
Linux日常之允许或禁止指定用户或IP进行SSH登录: https://blog.youkuaiyun.com/qq_37124744/article/details/83088410
-
Linux Bastion Hosts on the AWS Cloud: Quick Start Reference Deployment
8 附:bastion_bootstrap.sh
#!/bin/bash -e
# Bastion Bootstrapping
# The script is based on AWS basition quick start. More detail can been found at https://github.com/aws-quickstart/quickstart-linux-bastion.
# Configuration
PROGRAM='Linux Bastion'
##################################### Functions Definitions
# 本脚本只支持Linux操作系统。
function checkos () {
platform='unknown'
unamestr=`uname`
if [[ "${unamestr}" == 'Linux' ]]; then
platform='linux'
else
echo "[WARNING] This script is not supported on MacOS or FreeBSD"
exit 1
fi
echo "${FUNCNAME[0]} Ended"
}
# 初始化必要的目录和文件,并设置环境变量
# 其中在堡垒机上执行的所有命令将被记录在/var/log/bastion/bastion.log文件下。
function setup_environment_variables() {
# LOGGING CONFIGURATION
BASTION_MNT="/var/log/bastion"
BASTION_LOG="bastion.log"
echo "Setting up bastion session log in ${BASTION_MNT}/${BASTION_LOG}"
mkdir -p ${BASTION_MNT}
BASTION_LOGFILE="${BASTION_MNT}/${BASTION_LOG}"
BASTION_LOGFILE_SHADOW="${BASTION_MNT}/.${BASTION_LOG}"
touch ${BASTION_LOGFILE}
if ! [ -L "$BASTION_LOGFILE_SHADOW" ]; then
ln ${BASTION_LOGFILE} ${BASTION_LOGFILE_SHADOW}
fi
mkdir -p /usr/bin/bastion
touch /tmp/messages
chmod 770 /tmp/messages
export BASTION_MNT BASTION_LOG BASTION_LOGFILE BASTION_LOGFILE_SHADOW
}
function verify_dependencies(){
echo "${FUNCNAME[0]} Ended"
}
function usage() {
echo "$0 <usage>"
echo " "
echo "options:"
echo -e "--help \t Show options for this script"
echo -e "--banner \t Enable or Disable Bastion Message"
echo -e "--enable \t SSH Banner"
echo -e "--tcp-forwarding \t Enable or Disable TCP Forwarding"
echo -e "--x11-forwarding \t Enable or Disable X11 Forwarding"
}
function chkstatus () {
if [[ $? -eq 0 ]]
then
echo "Script [PASS]"
else
echo "Script [FAILED]" >&2
exit 1
fi
}
function osrelease () {
OS=`cat /etc/os-release | grep '^NAME=' | tr -d \" | sed 's/\n//g' | sed 's/NAME=//g'`
if [[ "${OS}" == "Ubuntu" ]]; then
echo "Ubuntu"
elif [[ "${OS}" == "CentOS Linux" ]]; then
echo "CentOS"
else
echo "Operating System Not Found"
fi
}
# 修改sshd_config文件,当用户在堡垒机上执行shell命令时,将首先自动执行定义的脚本文件/usr/bin/basition/shell
function harden_ssh_security () {
# Make OpenSSH execute a custom script on logins
echo -e "\nForceCommand /usr/bin/bastion/shell" >> /etc/ssh/sshd_config
cat <<'EOF' >> /usr/bin/bastion/shell
bastion_mnt="/var/log/bastion"
bastion_log="bastion.log"
# Check that the SSH client did not supply a command. Only SSH to instance should be allowed.
export Allow_SSH="ssh"
export Allow_SCP="scp"
if [[ -z $SSH_ORIGINAL_COMMAND ]] || [[ $SSH_ORIGINAL_COMMAND =~ ^$Allow_SSH ]] || [[ $SSH_ORIGINAL_COMMAND =~ ^$Allow_SCP ]]; then
#Allow ssh to instance and log connection
if [[ -z "$SSH_ORIGINAL_COMMAND" ]]; then
/bin/bash
exit 0
else
$SSH_ORIGINAL_COMMAND
fi
log_shadow_file_location="${bastion_mnt}/.${bastion_log}"
log_file=`echo "$log_shadow_file_location"`
DATE_TIME_WHOAMI="`whoami`:`date "+%Y-%m-%d %H:%M:%S"`"
LOG_ORIGINAL_COMMAND=`echo "$DATE_TIME_WHOAMI:$SSH_ORIGINAL_COMMAND"`
echo "$LOG_ORIGINAL_COMMAND" >> "${bastion_mnt}/${bastion_log}"
log_dir="/var/log/bastion/"
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
release=$(osrelease)
if [[ "${release}" == "CentOS" ]]; then
semanage fcontext -a -t ssh_exec_t /usr/bin/bastion/shell
fi
echo "${FUNCNAME[0]} Ended"
}
function setup_logs () {
echo "${FUNCNAME[0]} Started"
}
# 修改bashrc文件。当用户登录到堡垒机时,将自动执行bashrc文件。
function setup_os () {
echo "${FUNCNAME[0]} Started"
if [[ "${release}" == "CentOS" ]]; then
bash_file="/etc/bashrc"
else
bash_file="/etc/bash.bashrc"
fi
cat <<EOF >> "${bash_file}"
#Added by Linux bastion bootstrap
declare -rx IP=\$(echo \$SSH_CLIENT | awk '{print \$1}')
declare -rx BASTION_LOG=${BASTION_LOGFILE}
declare -rx PROMPT_COMMAND='history -a >(logger -t "[ON]:\$(date) [FROM]:\${IP} [USER]:\${USER} [PWD]:\${PWD}" -s 2>>\${BASTION_LOG})'
EOF
echo "Defaults env_keep += \"SSH_CLIENT\"" >> /etc/sudoers
if [[ "${release}" == "Ubuntu" ]]; then
user_group="ubuntu"
elif [[ "${release}" == "CentOS" ]]; then
user_group="root"
fi
chown root:"${user_group}" "${BASTION_MNT}"
chown root:"${user_group}" "${BASTION_LOGFILE}"
chown root:"${user_group}" "${BASTION_LOGFILE_SHADOW}"
chmod 662 "${BASTION_LOGFILE}"
chmod 662 "${BASTION_LOGFILE_SHADOW}"
chattr +a "${BASTION_LOGFILE}"
chattr +a "${BASTION_LOGFILE_SHADOW}"
touch /tmp/messages
chown root:"${user_group}" /tmp/messages
if [[ "${release}" == "CentOS" ]]; then
restorecon -v /etc/ssh/sshd_config
systemctl restart sshd
fi
if [[ "${release}" == "SLES" ]]; then
echo "0 0 * * * zypper patch --non-interactive" > ~/mycron
elif [[ "${release}" == "Ubuntu" ]]; then
apt-get install -y unattended-upgrades
echo "0 0 * * * unattended-upgrades -d" > ~/mycron
else
echo "0 0 * * * yum -y update --security" > ~/mycron
fi
crontab ~/mycron
rm ~/mycron
echo "${FUNCNAME[0]} Ended"
}
# 不允许登录到堡垒机上的用户能通过ps -ef看到别的用户的进程信息。
function prevent_process_snooping() {
# Prevent bastion host users from viewing processes owned by other users.
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
echo "${FUNCNAME[0]} Ended"
}
##################################### End Function Definitions
# Read the options from cli input
TEMP=`getopt -o h --longoptions help,banner:,enable:,tcp-forwarding:,x11-forwarding: -n $0 -- "$@"`
eval set -- "${TEMP}"
# Call checkos to ensure platform is Linux
checkos
# Verify dependencies are installed.
verify_dependencies
# Assuming it is, setup environment variables.
setup_environment_variables
# BANNER CONFIGURATION
ENABLE="true"
BANNER_FILE="/etc/ssh_banner"
BANNER_PATH="https://raw.githubusercontent.com/ksc-sbt/bastion/master/ssh-banner.txt"
if [[ ${ENABLE} == "true" ]];then
if [[ -z ${BANNER_PATH} ]];then
echo "BANNER_PATH is null skipping ..."
else
echo "BANNER_PATH = ${BANNER_PATH}"
echo "Creating Banner in ${BANNER_FILE}"
echo "curl -s ${BANNER_PATH} > ${BANNER_FILE}"
curl -s ${BANNER_PATH} > ${BANNER_FILE}
if [[ -e ${BANNER_FILE} ]] ;then
echo "[INFO] Installing banner ... "
echo -e "\n Banner ${BANNER_FILE}" >>/etc/ssh/sshd_config
else
echo "[INFO] banner file is not accessible skipping ..."
exit 1;
fi
fi
else
echo "Banner message is not enabled!"
fi
release=$(osrelease)
if [[ "${release}" == "Operating System Not Found" ]]; then
echo "[ERROR] Unsupported Linux Bastion OS"
exit 1
else
setup_os
setup_logs
fi
prevent_process_snooping
echo "Bootstrap complete."