技术岗怎样做工作交接
本文节选择《Netkiller Management 手札》作者:netkiller
在国内工作交接如同家常便饭,有数据显示员工服务于公司的平均时间,其中80后平均是3年时间,90后平均为2~2.5,95后约半年~1.5年。如此频繁地更换工作不仅仅是员工自身问题,公司用人单位也存在一定问题,这里就不讨论了。
在早期管理学还未在中国普及的时候,50/60/70后沿用了自古以来的老旧的管理思想,搞仁制和驭人术那套,如今已经是2022年了,管理学已经非常成熟,大学有专门管理课,社会上有专业的管理培训,但仍有大量公司在采用中式管理,且管理层搞得不亦乐乎,并未有改变的想法。
国内公司存在的问题:
- 管理混乱,换个领导就意味着换套新流程
- 口头管理,没有形成流程和文档化
- 驭人术,讲忠诚和服从性
所以在工作中,工作交接是不可避免的,无论是用人单位找到你,还是你主动应聘岗位,工作交接都是一项极具挑战的工作,俗称“擦屁股”,我们怎样做好工作交接呢?
工作交接过程
任何工作交接都会丢失80%内容,交接者只能接受20%的工作内容。
丢失的内容有可能是交接者没有想到,交接者故意隐瞒,交接者故意挖坑,交接者说了但是接受者没听懂或忘记了,总之工作不可能达到 100% 的交接。
尤其是国内企业和雇员紧张的劳动关系,几乎大部分的工作交接都不太顺利。
同时离职员工去下家公司也同样面临严峻挑战的工作交接过程,似乎这是一个无解的死循环。
即使是我们口中常说的大厂也存在上述问题。
工作交接过程中可能遇到的问题:
- 没有足够的书面资料
- 口头只给你说一次
- 交接者故意隐瞒信息
- 交接者故意给你挖坑
- 交接者不主动、敷衍、不配合
- 没有给你足够的时间学习、理解、吸收
- 你不问,对方不会主动给你讲
你能做的是尽量获得更多交接文档,很多事你要先想到,主动问对方,交接者没有责任和义务帮你,他想尽快甩锅走人,你只能求菩萨保佑它跟用人带单位没有纠纷。
这导致很多时候工作交接要靠我们自己,同时我们离职的时候也会用这些办法对付接收我们工作的人,呵呵!!!
确认入口
以技术工作交接为例,如何快速摸清系统,掌握各系统模块之间的关系呢?
互联网入口都有哪些:
- 网站入口
- 手机App入口
- 小程序/公众号/第三方入口
- TCP/UDP Socket 入口
域名检查
使用 nslookup/dig 等工具检查域名
- A 记录,主机解析
- MX 记录,邮件交换记录
- TXT 记录,一些特定服务
- AAAA 记录,IPv6 主机解析
- NS 记录
然后在登陆的DNS管理界面查漏补缺,这里重点是 MX 记录,很多时候会忽略,导致邮件服务不能用。
IP地址检查
网站入口通常是域名或IP地址,例如我的域名是 www.netkiller.cn,使用 ping 工具查看其IP地址
[root@netkiller ~]# ping www.netkiller.cn
手机App链接的API地址需要抓包工具
网络设备
备份配置文件
登陆网络设备,备份配置文件,然后分析网络拓扑,如果有交接文档,就按照文档核对 vlan和每个路由器和交换机端口功能。
Cisco 网络设备使用 show running-config 查看配置文件
Router#show running-config
Router#show startup-config
H3C 网络设备使用 display current-configuration 查看配置文件
[WA2220E-AG]display current-configuration
#
version 5.20, Release 1110P01
#
sysname WA2220E-AG
#
domain default enable system
#
telnet server enable
#
port-security enable
#
vlan 1
#
radius scheme system
#
domain system
access-limit disable
state active
idle-cut disable
self-service-url disable
Juniper 网络设备,使用 get config 查看配置文件
[root@netkiller ~]# ssh neo@192.168.1.1
neo@192.168.3.1's password:
Remote Management Console
firewall-> get config
Total Config size 17376:
set clock ntp
set clock timezone 7
set vrouter trust-vr sharable
set vrouter "untrust-vr"
exit
set vrouter "trust-vr"
unset auto-route-export
exit
...
...
...
exit
set vrouter "untrust-vr"
exit
set vrouter "trust-vr"
exit
firewall->
这些网络设备如何使用,请参考《Netkiller Network 手札》
绘制网络拓扑图
几乎90%(可以我说少了)公司,在IT这块的管理十分混乱,走进机房,网线乱如麻,你根本不知道那根网线链接了什么设备,我们需要先理清重点设备的链接拓扑图。
这里以 H3C 为例,其他设备操作方式大同小异,下面是找到接口对等设备的IP地址
<H3C>display arp interface GE1/0/32
Type: S-Static D-Dynamic O-Openflow R-Rule M-Multiport I-Invalid
IP address MAC address VLAN/VSI name Interface Aging Type
172.16.200.75 b07b-2523-5326 200 GE1/0/32 501 D
通过 mac 地址找接口
<H3C>display arp all | include 6227-d242-269e
172.16.0.68 6227-d242-269e 10 GE1/0/3 1085 D
通过 ip 地址找接口
<H3C>display arp all | include 172.16.200.102
172.16.200.102 001e-67fa-df92 200 GE1/0/36 282 D
服务器系统检查
当我们知道服务器IP地址之后就可以登录服务器了
[root@netkiller ~]# ssh root@www.netkiller.cn
登陆服务器之后首先快速检查是否有安全问题
检查用户权限
[root@netkiller ~]# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin
systemd-resolve:x:193:193:systemd Resolver:/:/sbin/nologin
tss:x:59:59:Account used for TPM access:/dev/null:/sbin/nologin
polkitd:x:998:996:User for polkitd:/:/sbin/nologin
unbound:x:997:993:Unbound DNS resolver:/etc/unbound:/sbin/nologin
libstoragemgmt:x:996:992:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
setroubleshoot:x:995:991::/var/lib/setroubleshoot:/sbin/nologin
cockpit-ws:x:994:990:User for cockpit web service:/nonexisting:/sbin/nologin
cockpit-wsinstance:x:993:989:User for cockpit-ws instances:/nonexisting:/sbin/nologin
sssd:x:992:988:User for sssd:/:/sbin/nologin
chrony:x:991:987::/var/lib/chrony:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
nscd:x:28:28:NSCD Daemon:/:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
docker:x:986:986:Container Administrator:/home/docker:/bin/bash
git:x:1000:1000::/home/git:/bin/bash
caddy:x:985:984:Caddy web server:/var/lib/caddy:/sbin/nologin
nginx:x:984:983:Nginx web server:/var/lib/nginx:/sbin/nologin
通常除了 root 用户,小于1000的UID的用户 SHELL 应该是 /sbin/nologin
重点检查拥有 shell 权限的用户,非必要全部改为 /sbin/nologin
[root@netkiller ~]# cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
docker:x:986:986:Container Administrator:/home/docker:/bin/bash
git:x:1000:1000::/home/git:/bin/bash
检查用户是否激活,并设置密码
[root@netkiller ~]# cat /etc/shadow
root:$6$XyW4o/lZWdu$VsjNYW8nVcE63cWwAxLxBe5s22vt4hQCOivzxo5RQ3rGbcBkfWnc/ATiy073D7/aIHQaDZplIJWz51s4Pzkn0.:19173:0:99999:7:::
bin:*:18505:0:99999:7:::
daemon:*:18505:0:99999:7:::
adm:*:18505:0:99999:7:::
lp:*:18505:0:99999:7:::
sync:*:18505:0:99999:7:::
shutdown:*:18505:0:99999:7:::
halt:*:18505:0:99999:7:::
mail:*:18505:0:99999:7:::
operator:*:18505:0:99999:7:::
games:*:18505:0:99999:7:::
ftp:*:18505:0:99999:7:::
nobody:*:18505:0:99999:7:::
dbus:!!:19136::::::
systemd-coredump:!!:19136::::::
systemd-resolve:!!:19136::::::
tss:!!:19136::::::
polkitd:!!:19136::::::
unbound:!!:19136::::::
libstoragemgmt:!!:19136::::::
setroubleshoot:!!:19136::::::
cockpit-ws:!!:19136::::::
cockpit-wsinstance:!!:19136::::::
sssd:!!:19136::::::
chrony:!!:19136::::::
sshd:!!:19136::::::
tcpdump:!!:19136::::::
nscd:!!:19136::::::
postfix:!!:19136::::::
docker:$6$6.KJvlfezlr7q09N$Xo83rIqChY0sLrvyCGnNYqPpCsREk1h1En7eNwZBV9sjN6XVOO9xgjuKGn..tAhElYK1SLI6mvZa6pxsCcuqb/:19177:0:99999:7:::
git:$6$EcduJ7Z1HAZWhRPN$wyG7OOpQaw84FgvAsXBPUKr.dZWEDIaWhMKeoEuNRvpfzvoeKo4gei028lSCm./nAvFqRpos/2Ng4ARHR5FRj.:19173:0:99999:7:::
caddy:!!:19177::::::
nginx:!!:19192::::::
!! 和 * 是未设置密码,该用户无法登陆系统,$6$ 表示该用户有密码
这三个用户是有密码的
[root@netkiller ~]# cat /etc/shadow | grep '\$6\#39;
root:$6$XyW4o/lZWdu$VsjNYW8nVcE63cWwAxLxBe5s22vt4hQCOivzxo5RQ3rGbcBkfWnc/ATiy073D7/aIHQaDZplIJWz51s4Pzkn0.:19173:0:99999:7:::
docker:$6$6.KJvlfezlr7q09N$Xo83rIqChY0sLrvyCGnNYqPpCsREk1h1En7eNwZBV9sjN6XVOO9xgjuKGn..tAhElYK1SLI6mvZa6pxsCcuqb/:19177:0:99999:7:::
git:$6$EcduJ7Z1HAZWhRPN$wyG7OOpQaw84FgvAsXBPUKr.dZWEDIaWhMKeoEuNRvpfzvoeKo4gei028lSCm./nAvFqRpos/2Ng4ARHR5FRj.:19173:0:99999:7:::
锁定/解锁用户
发现可疑用户,我们可以先把它锁掉,让他登陆不了。使用 passwd -l 给用户加锁,-u 解锁。
[root@netkiller ~]# passwd --help
Usage: passwd [OPTION...] <accountName>
-k, --keep-tokens keep non-expired authentication tokens
-d, --delete delete the password for the named account (root only); also removes password lock if any
-l, --lock lock the password for the named account (root only)
-u, --unlock unlock the password for the named account (root only)
-e, --expire expire the password for the named account (root only)
-f, --force force operation
-x, --maximum=DAYS maximum password lifetime (root only)
-n, --minimum=DAYS minimum password lifetime (root only)
-w, --warning=DAYS number of days warning users receives before password expiration (root only)
-i, --inactive=DAYS number of days after password expiration when an account becomes disabled (root only)
-S, --status report password status on the named account (root only)
--stdin read new tokens from stdin (root only)
Help options:
-?, --help Show this help message
--usage Display brief usage message
例如我们要禁止 git 用户登陆系统
[root@netkiller ~]# passwd -l git
Locking password for user git.
passwd: Success
恢复 git 用户登陆权限
[root@netkiller ~]# passwd -u git
Unlocking password for user git.
passwd: Success
实际的加锁与解锁的过程就是在 shadow 文件中,密码前面增加 !! 符号。
[root@netkiller ~]# passwd -l git
Locking password for user git.
passwd: Success
[root@netkiller ~]# cat /etc/shadow | grep 'git'
git:!!$6$EcduJ7Z1HAZWhRPN$wyG7OOpQaw84FgvAsXBPUKr.dZWEDIaWhMKeoEuNRvpfzvoeKo4gei028lSCm./nAvFqRpos/2Ng4ARHR5FRj.:19173:0:99999:7:::
[root@netkiller ~]# passwd -u git
Unlocking password for user git.
passwd: Success
[root@netkiller ~]# cat /etc/shadow | grep 'git'
git:$6$EcduJ7Z1HAZWhRPN$wyG7OOpQaw84FgvAsXBPUKr.dZWEDIaWhMKeoEuNRvpfzvoeKo4gei028lSCm./nAvFqRpos/2Ng4ARHR5FRj.:19173:0:99999:7:::
检查端口
非法进入服务器必须某种服务端口,我们确认用户安全后,接下来要做的就是扫描端口,看看服务器上开了哪些端口。
[root@netkiller ~]# dnf install -y nmap
nmap 使用方法请看我的《Netkiller Linux 手札》本文只教方*论法**。
[root@netkiller ~]# nmap www.netkiller.cn
Starting Nmap 7.70 ( https://nmap.org ) at 2022-07-23 16:23 CST
Nmap scan report for chat.netkiller.cn (8.219.73.35)
Host is up (0.00041s latency).
Not shown: 993 filtered ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
3389/tcp closed ms-wbt-server
8000/tcp closed http-alt
8080/tcp closed http-proxy
9000/tcp closed cslistener
Nmap done: 1 IP address (1 host up) scanned in 25.40 seconds
通过端口找进程,可以使用 ss 和 netstat 两个工具完成
[root@netkiller ~]# netstat -antup|grep 80
tcp 0 0 172.22.119.108:20507 100.103.15.60:80 ESTABLISHED 1490/AliYunDun
tcp6 0 0 :::80 :::* LISTEN 1629762/caddy
[root@netkiller ~]# ss -lntp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1189,fd=5))
LISTEN 0 1024 127.0.0.1:2019 0.0.0.0:* users:(("caddy",pid=1629762,fd=3))
LISTEN 0 1024 *:80 *:* users:(("caddy",pid=1629762,fd=8))
LISTEN 0 1024 *:443 *:* users:(("caddy",pid=1629762,fd=7))
这里可以看到 80 端口是 1629762 进程监听的,该进程是 caddy 它是一个 web 服务器
通过进程找进程ID
[root@netkiller ~]# pgrep caddy
1629762
检查进程
Linux 系统进程带有中括号的是内核进程,除此之外都需要一一排查
[root@netkiller ~]# ps ax | grep '\['
2 ? S 0:01 [kthreadd]
3 ? I< 0:00 [rcu_gp]
4 ? I< 0:00 [rcu_par_gp]
6 ? I< 0:00 [kworker/0:0H-events_highpri]
9 ? I< 0:00 [mm_percpu_wq]
10 ? S 0:00 [rcu_tasks_rude_]
11 ? S 0:00 [rcu_tasks_trace]
12 ? S 0:01 [ksoftirqd/0]
13 ? I 9:14 [rcu_sched]
14 ? S 0:00 [migration/0]
15 ? S 0:00 [watchdog/0]
16 ? S 0:00 [cpuhp/0]
17 ? S 0:00 [cpuhp/1]
18 ? S 0:00 [watchdog/1]
19 ? S 0:00 [migration/1]
20 ? S 0:00 [ksoftirqd/1]
22 ? I< 0:00 [kworker/1:0H-events_highpri]
23 ? S 0:00 [cpuhp/2]
24 ? S 0:01 [watchdog/2]
25 ? S 0:00 [migration/2]
26 ? S 0:00 [ksoftirqd/2]
28 ? I< 0:00 [kworker/2:0H-events_highpri]
29 ? S 0:00 [cpuhp/3]
30 ? S 0:01 [watchdog/3]
31 ? S 0:00 [migration/3]
32 ? S 0:00 [ksoftirqd/3]
34 ? I< 0:00 [kworker/3:0H-events_highpri]
35 ? S 0:00 [cpuhp/4]
36 ? S 0:01 [watchdog/4]
37 ? S 0:00 [migration/4]
38 ? S 0:00 [ksoftirqd/4]
40 ? I< 0:00 [kworker/4:0H-events_highpri]
41 ? S 0:00 [cpuhp/5]
42 ? S 0:01 [watchdog/5]
43 ? S 0:00 [migration/5]
44 ? S 0:00 [ksoftirqd/5]
46 ? I< 0:00 [kworker/5:0H-events_highpri]
47 ? S 0:00 [cpuhp/6]
48 ? S 0:01 [watchdog/6]
49 ? S 0:00 [migration/6]
50 ? S 0:00 [ksoftirqd/6]
52 ? I< 0:00 [kworker/6:0H-events_highpri]
53 ? S 0:00 [cpuhp/7]
54 ? S 0:02 [watchdog/7]
55 ? S 0:00 [migration/7]
56 ? S 0:00 [ksoftirqd/7]
58 ? I< 0:00 [kworker/7:0H-events_highpri]
67 ? S 0:00 [kdevtmpfs]
68 ? I< 0:00 [netns]
69 ? S 0:00 [kauditd]
70 ? S 0:01 [khungtaskd]
71 ? S 0:00 [oom_reaper]
72 ? I< 0:00 [writeback]
73 ? S 0:00 [kcompactd0]
74 ? SN 0:00 [ksmd]
75 ? SN 0:18 [khugepaged]
76 ? I< 0:00 [crypto]
77 ? I< 0:00 [kintegrityd]
78 ? I< 0:00 [kblockd]
79 ? I< 0:00 [blkcg_punt_bio]
80 ? I< 0:00 [tpm_dev_wq]
81 ? I< 0:00 [md]
82 ? I< 0:00 [edac-poller]
83 ? S 0:00 [watchdogd]
84 ? I< 0:01 [kworker/0:1H-kblockd]
118 ? S 0:00 [kswapd0]
224 ? I< 0:00 [kthrotld]
225 ? I< 0:00 [acpi_thermal_pm]
226 ? I< 0:00 [kmpath_rdacd]
227 ? I< 0:00 [kaluad]
229 ? I< 0:02 [kworker/4:1H-kblockd]
230 ? I< 0:00 [ipv6_addrconf]
232 ? I< 0:00 [kstrp]
313 ? I< 0:01 [kworker/5:1H-kblockd]
319 ? I< 0:01 [kworker/2:1H-kblockd]
347 ? I< 0:14 [kworker/7:1H-xfs-log/vda1]
350 ? I< 0:01 [kworker/3:1H-kblockd]
355 ? I< 0:01 [kworker/1:1H-kblockd]
361 ? I< 0:01 [kworker/6:1H-kblockd]
501 ? I< 0:00 [ata_sff]
502 ? S 0:00 [scsi_eh_0]
503 ? I< 0:00 [scsi_tmf_0]
504 ? S 0:00 [scsi_eh_1]
505 ? I< 0:00 [scsi_tmf_1]
533 ? I< 0:00 [xfsalloc]
535 ? I< 0:00 [xfs_mru_cache]
536 ? I< 0:00 [xfs-buf/vda1]
537 ? I< 0:00 [xfs-conv/vda1]
538 ? I< 0:00 [xfs-cil/vda1]
539 ? I< 0:00 [xfs-reclaim/vda]
540 ? I< 0:00 [xfs-blockgc/vda]
542 ? I< 0:00 [xfs-log/vda1]
543 ? S 2:57 [xfsaild/vda1]
880 ? I< 0:00 [nfit]
1636473 ? I 0:01 [kworker/5:2-events_power_efficient]
1636635 ? I 0:07 [kworker/7:0-events]
1636884 ? I 0:00 [kworker/6:0-events]
1636886 ? I 0:00 [kworker/2:3-events]
1637134 ? I 0:00 [kworker/1:0-events]
1637224 ? I 0:00 [kworker/2:0]
1637273 ? I 0:00 [kworker/0:3-mm_percpu_wq]
1637275 ? I 0:00 [kworker/u16:0-events_unbound]
1637290 ? I 0:00 [kworker/6:2-mm_percpu_wq]
1637344 ? I 0:00 [kworker/1:1]
1637352 ? Ss 0:00 sshd: root [priv]
1637362 ? I 0:00 [kworker/0:2-events]
1637501 ? I 0:00 [kworker/4:1-events]
1637953 ? I 0:00 [kworker/3:0-cgroup_pidlist_destroy]
1637956 ? I< 0:00 [ib-comp-wq]
1637957 ? I< 0:00 [kworker/u17:0]
1637958 ? I< 0:00 [ib-comp-unb-wq]
1637960 ? I< 0:00 [ib_mcast]
1637961 ? I< 0:00 [ib_nl_sa_wq]
1637965 ? I 0:00 [kworker/5:0]
1637976 ? I 0:00 [kworker/4:0-xfs-sync/vda1]
1637979 ? I 0:00 [kworker/7:2]
1637981 ? I 0:00 [kworker/3:3-cgroup_destroy]
1637986 ? I 0:00 [kworker/u16:1-events_unbound]
1638007 pts/0 S+ 0:00 grep --color=auto \[
使用 grep -v 排除所有内核进程,这样看着舒服一些。
[root@netkiller ~]# ps ax | grep -v '\['
PID TTY STAT TIME COMMAND
1 ? Ss 3:08 /usr/lib/systemd/systemd --switched-root --system --deserialize 17
649 ? Ss 0:21 /usr/lib/systemd/systemd-journald
681 ? Ss 0:02 /usr/lib/systemd/systemd-udevd
711 ? S<sl 0:04 /sbin/auditd
716 ? S< 0:01 /usr/sbin/sedispatch
759 ? Ss 0:03 /usr/bin/lsmd -d
769 ? Ss 0:00 /usr/sbin/smartd -n -q never
770 ? Ssl 0:01 /usr/lib/polkit-1/polkitd --no-debug
779 ? Ss 0:14 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
788 ? Ss 0:00 /usr/sbin/mcelog --ignorenodev --daemon --foreground
794 ? S 0:08 /usr/sbin/chronyd
974 ? Ss 0:08 /usr/lib/systemd/systemd-logind
1023 ? Ssl 1:03 /usr/sbin/NetworkManager --no-daemon
1027 ? Ssl 76:19 /usr/libexec/platform-python -Es /usr/sbin/tuned -l -P
1189 ? Ss 0:01 /usr/sbin/sshd -D -oCiphers=aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes256-cbc,aes128-gcm@openssh.com,aes128-ctr,aes128-cbc -oMACs=hmac-sha2-256-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha1,umac-128@openssh.com,hmac-sha2-512 -oGSSAPIKexAlgorithms=gss-curve25519-sha256-,gss-nistp256-sha256-,gss-group14-sha256-,gss-group16-sha512-,gss-gex-sha1-,gss-group14-sha1- -oKexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1 -oHostKeyAlgorithms=ecdsa-sha2-nistp256,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com,ssh-rsa,ssh-rsa-cert-v01@openssh.com -oPubkeyAcceptedKeyTypes=ecdsa-sha2-nistp256,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com,ssh-rsa,ssh-rsa-cert-v01@openssh.com -oCASignatureAlgorithms=ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,rsa-sha2-256,rsa-sha2-512,ssh-rsa
1201 ? Ss 0:00 /usr/sbin/atd -f
1233 tty1 Ss+ 0:00 /sbin/agetty -o -p -- \u --noclear tty1 linux
1234 ttyS0 Ss+ 0:00 /sbin/agetty -o -p -- \u --keep-baud 115200,38400,9600 ttyS0 vt220
1461 ? S<sl 22:04 /usr/local/aegis/aegis_update/AliYunDunUpdate
1490 ? S<sl 412:12 /usr/local/aegis/aegis_client/aegis_11_25/AliYunDun
1652 ? Ss 0:02 /usr/sbin/crond -n
1702 ? Ssl 1:25 /usr/sbin/rsyslogd -n
4186 ? Ssl 35:58 /usr/bin/containerd
4200 ? Ssl 26:56 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
221773 ? Ss 0:01 /usr/sbin/sssd -i --logger=files
221775 ? S 0:09 /usr/libexec/sssd/sssd_be --domain implicit_files --uid 0 --gid 0 --logger=files
221776 ? S 3:32 /usr/libexec/sssd/sssd_nss --uid 0 --gid 0 --logger=files
298641 ? Ssl 31:55 /usr/local/share/aliyun-assist/2.2.3.309/aliyun-service
298799 ? Ssl 5:34 /usr/local/share/assist-daemon/assist_daemon
1629762 ? Ssl 0:23 /usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
1637356 ? Ss 0:00 /usr/lib/systemd/systemd --user
1637358 ? S 0:00 (sd-pam)
1637366 ? S 0:00 sshd: root@pts/0
1637367 pts/0 Ss 0:00 -bash
1638004 pts/0 R+ 0:00 ps ax
对于可疑进程一律找到它所在位置,先kill掉,然后去掉可执行权限,归档备份。
例如我们对 caddy 下手,首先查看进程位置 /usr/bin/caddy
[root@netkiller ~]# ps ax |grep caddy
1629762 ? Ssl 0:23 /usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
1637983 pts/0 S+ 0:00 grep --color=auto caddy
看看是否有系统启动服务
systemctl stop caddy
systemctl disable caddy
现在就禁用了,如果这个程序是手工安装没有systemd,我们就需要 chmod -x /usr/bin/caddy
以上是 caddy 为例,其他服务也都如此。
检查配置文件
确认服务器使用的是什么操作系统,然后用这个版本安装一个干净的环境,在新服务器和当前要检查的服务器上分别执行下面命令
[root@netkiller ~]# find /etc/ > etc.lst
[root@netkiller ~]# find /usr/etc/ > usr.etc.lst
[root@netkiller ~]# find /usr/local/etc/ > usr.etc.lst
然后使用文件比较工具比较文件列表,差异的部分,就是新增的文件。你也可以讲两个服务器的 etc 目录复制出来,使用工具比较他们的差异。
容器的检查
目前许多公司都在使用 Docker / Kubernetes 部署系统,其实容器并非安全,在容器镜像中藏点私货是非常容易的,Docker 官方提供了安全扫描工具
[root@netkiller ~]# docker scan
Docker Scan relies upon access to Snyk, a third party provider, do you consent to proceed using Snyk? (y/N)
我们安装物理机所用的系统通常是去官网*载下**,很多容器的制作并为使用官方镜像,同时会做 md5sum 校验,所以是安全的。容器镜像安全更多是来自无序的继承,经过多次继承我们不知道里面做了那些变化,所以选择基础镜像非常重要。
[root@netkiller ~]# cat Dockerfile | grep FROM
FROM nginx:latest
如果不是官方镜像,需要格外注意
云安全检查
云平台通常网络分成WLAN和LAN两个部分,有些平台WLAN 是挂载到 eth0 上,有些平台云主机只有内网IP,WLAN是映射到内网IP上。
采用的手段跟上面一样,扫描端口,检查安全组规则,弹性IP和SLB策略。
原则是,WLAN外网只允许通过特定端口例如80/443,剩下所有服务在LAN上通信。
工作交接期间,只开放80/443端口,完成交接后,并做了安全排查之后,逐渐开放需要的端口,建议限制来源IP地址,例如只允许从办公室访问。
系统备份
以上检查的所有项的配置文件都需要备份一份,以防万一,这个万一存在很多不确定性因素,你懂的
绘制网络和服务器/容器拓扑图
使用visio等软件绘制网络和服务器/容器拓扑图
部署运作机制
这个步骤是搞清楚代码从开发到生产环境是怎么部署的,如果使用了CI/CD技术,就从持续集成和部署着手看,可以一目了然。如果是手工部署,要亲力亲为自己做一遍,同时将CI/CD就此机会做起来。
举一个例子,比如有一个项目教 api.netkiller.cn
代码库中找到这个项目
编译和打包
目前国内最主流搭配是前端 node 后端 java,当然也有少量项目使用 PHP、Python和Go,总体大同小异。
如果是 node.js 项目通常是 webpack 无非就是下面两步
npm install --registry=https://registry.npm.taobao.org
npm run build:prod
Java 项目
mvn clean package
搞清楚配置文件
前端 NodeJS 项目配置通常只链接后端,配置涉及较少,相对容易掌握。
Java 项目配置文件放在 src/main/resources/ 中 Springboot 项目配置文件是 src/main/resources/application.yml,Springcloud 的配置文件是 src/main/resources/bootstrap.yml
也有使用 application.properties 和 bootstrap.properties
我们既要检查配置文件中都链接了那些服务,还要检查配置是否合理,例如链接池的最大链接数量,链接超时时间等等。
如果使用配置中心,需要进入配置中心查看配置文件
绘制业务关系拓扑图
走一遍业务逻辑,从域名进入网站到数据保存到数据,这中间经过了那些服务,他们的调用关系是什么,画一张图,让你一清二楚。
如果有链路追踪能让你更快完成这步工作,如果没有,这也是未来要做的工作,这时就需要结合各种配置文件,或者询问各种相关部门和人员来完成这个拓扑图。
备份
- 备份代码
- 备份配置文件
将备份过程放在CI/CD过程中,让备份自动化
接手代码
程序猿常常自嘲是粪海狂蛆!陈年的粪缸,经过发酵、沉淀、分解已经没有屎尿的味道,你千万别去动它。
国内大部分项目都是平均三年经验的开发人写的,同时90后平均不到两年就会换工作,你别期望代码质量有多高,你别更别期望问同事能得到答案。
常态是,大部分情况下,只要修改代码就产生新bug!延伸阅读《程序猿说的「优化」是什么意思?》
代码审查
代码审查只是一句口号历来如此,很多团队都说在做,实际情况你懂的。但是此时一些对外的服务真的有必要做一次 code review,我的职业生涯中,曾经遇到过离职人员埋后门的情况。
经过前面的服务器排查,通过SSH登陆服务器搞破坏的可能性是极小的,更多的漏洞是代码漏洞和业务漏洞。
代码扫描
使用代码扫描工具,例如 SonarQube 扫描lib和引用第三方包的安全漏洞,及时升级第三方包,修复存在安全的代码。
如果你期待代码扫描能帮你找出业务漏洞,纯属扯淡,我们使用代码扫描更多是发现 pom.xml 中引用第三方库已知的 CVE 漏洞。
收缩技术栈
接手代码之后,首要解决的是能让它工作起来,然后着手优化代码,绝大多数人的思维是加法思维,他们会使用许多技术来完成一件事,这是错误的。
正确的做法是使用一种技术完成所有工作。