-
Notifications
You must be signed in to change notification settings - Fork 1
/
spring.xml
1609 lines (1536 loc) · 46.7 KB
/
spring.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V5.0//EN"
"/usr/share/xml/docbook/schema/dtd/5.0/docbook.dtd" [
<!ENTITY article.author.xml SYSTEM "common/article.author.xml">
<!ENTITY book.info.legalnotice.xml SYSTEM "common/book.info.legalnotice.xml">
<!ENTITY book.info.abstract.xml SYSTEM "common/book.info.abstract.xml">
]>
<article xml:base="http://netkiller.github.io/journal/spring.html" xmlns="http://docbook.org/ns/docbook" xml:lang="zh-cn">
<articleinfo>
<title>Spring cloud 安全部署与性能优化</title>
<subtitle>http://www.netkiller.cn/journal/spring.html</subtitle>
&article.author.xml;
&book.info.legalnotice.xml;
<abstract>
</abstract>
&book.info.abstract.xml;
<keywordset>
<keyword>spring, spring cloud</keyword>
<keyword></keyword>
<keyword></keyword>
<keyword></keyword>
</keywordset>
<pubdate>$Date$</pubdate>
<release>$Id$</release>
</articleinfo>
<section id="env">
<title>环境安装</title>
<section>
<title>操作系统初始化</title>
<para>操作系统按完成后,使用下面脚本做一次初始化</para>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/os/personalise.sh | bash
]]>
</screen>
</section>
<section>
<title>安装 Nginx </title>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/web/nginx/stable/nginx.sh | bash
]]>
</screen>
</section>
<section>
<title>安装数据库</title>
<section>
<title>MySQL</title>
<para>5.7</para>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/database/mysql/5.7/mysql.server.sh | bash
]]>
</screen>
<para>安装完成会看到下面输出</para>
<screen>
<![CDATA[
2019-06-04T08:54:24.419092Z 1 [Note] A temporary password is generated for root@localhost: 8X!pE(o+urv;
]]>
</screen>
<para></para>
<para>8.0</para>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/database/mysql/8.0/server.sh | bash
curl -s https://raw.githubusercontent.com/oscm/shell/master/database/mysql/8.0/client.sh | bash
]]>
</screen>
</section>
<section>
<title>PostgreSQL</title>
<para>PostgreSQL 9.4</para>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/database/postgresql/postgresql94-centos7.sh | bash
]]>
</screen>
</section>
<section>
<title>Redis</title>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/database/redis/source/redis-5.0.5.sh | bash
]]>
</screen>
</section>
</section>
<section>
<title>RabbitMQ</title>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/queue/rabbitmq/rabbitmq-server-3.7.15.sh | bash
]]>
</screen>
</section>
<section>
<title>OpenJDK</title>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/lang/java/openjdk/java-1.8.0-openjdk.sh | bash
]]>
</screen>
<section>
<title>Maven</title>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/lang/java/maven/apache-maven-3.6.1.sh | bash
]]>
</screen>
</section>
<section>
<title>Gradle</title>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/lang/java/gradle/gradle-5.4.1.sh | bash
]]>
</screen>
</section>
</section>
<section>
<title>Node</title>
<para>前端开发会用到Node.js</para>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/lang/node.js/binrary/node-v12.4.0.sh | bash
]]>
</screen>
</section>
<section>
<title>Gitlab</title>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/project/gitlab/gitlab.centos7.sh | bash
]]>
</screen>
<para>Gitlab 配置请参考 《Netkiller Project 手札》</para>
<section>
<title>Gitlab runner</title>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/project/gitlab/gitlab-runner.sh | bash
]]>
</screen>
<para>java 编译环境</para>
<para>去 Oracle 网站下载 java 8 jdk-8u212-linux-x64.rpm</para>
<screen>
<![CDATA[
yum localinstall jdk-8u212-linux-x64.rpm
curl -s https://raw.githubusercontent.com/oscm/shell/master/project/git.sh | bash
curl -s https://raw.githubusercontent.com/oscm/shell/master/lang/java/maven/apache-maven-3.6.1.sh | bash
]]>
</screen>
</section>
</section>
</section>
<section id="os">
<title>操作系统配置与优化</title>
<para>操作系统要求 CentOS 7 Minimal ISO</para>
<section>
<title>域名</title>
<section>
<title>配置 DNS</title>
<para>修改 /etc/resolv.conf 配置 DNS 确保域名解析正确</para>
<screen>
<![CDATA[
echo -ne "
search example.com
nameserver 208.67.222.222
nameserver 202.67.220.220
nameserver 8.8.8.8
nameserver 4.4.4.4
" > /etc/resolv.conf
]]>
</screen>
</section>
<section>
<title>/etc/hosts</title>
<para>DNS 解析有延迟,很多不可控因素,将域名写入 /etc/hosts 更为保险</para>
<screen>
<![CDATA[
192.168.1.1 www.netkiller.cn
192.168.1.2 api.netkiller.cn
192.168.1.3 db.netkiller.cn
]]>
</screen>
<para>使用域名链接数据的例子</para>
<screen>
<![CDATA[
spring.datasource.url=jdbc:mysql://db.netkiller.cn:3306/neo
]]>
</screen>
<para>DNS 不可靠的原因分析,因为DNS使用UDP传输,网络拥堵,电磁干扰等等都能导致丢包。</para>
</section>
</section>
<section>
<title>历史记录操作留痕</title>
<para>定义 .history 文件格式,记录每一步操作,便于查看什么时间执行了什么命令</para>
<para>通过~/.bash_history文件记录系统管理员的操作记录,定制.bash_history格式</para>
<screen>
<![CDATA[
HISTSIZE=1000
HISTFILESIZE=2000
HISTTIMEFORMAT="%Y-%m-%d-%H:%M:%S "
export HISTTIMEFORMAT
]]>
</screen>
<para>看看实际效果</para>
<screen>
<![CDATA[
$ history | head
1 2012-02-27-09:10:45 do-release-upgrade
2 2012-02-27-09:10:45 vim /etc/network/interfaces
3 2012-02-27-09:10:45 vi /etc/network/interfaces
4 2012-02-27-09:10:45 ping www.163.com
]]>
</screen>
</section>
<section>
<title>临时文件安全</title>
<para>临时文件不应该有执行权限</para>
<para>/tmp</para>
<screen>
<![CDATA[
/dev/sda3 /tmp ext4 nosuid,noexec,nodev,rw 0
]]>
</screen>
<para>同时使用符号连接将/var/tmp 指向 /tmp</para>
<para>/dev/shm</para>
<screen>
<![CDATA[
none /dev/shm tmpfs defaults,nosuid,noexec,rw 0 0
]]>
</screen>
</section>
<section>
<title>执行权限 </title>
<para>以数据库为例,从安全角度考虑我们需要如下更改</para>
<screen>
<![CDATA[
chown mysql:mysql /usr/bin/mysql*
chmod 700 /usr/bin/mysql*
]]>
</screen>
<para>mysql用户是DBA专用用户, 其他用户将不能执行mysql等命令。</para>
</section>
<section>
<title>Linux 系统资源调配</title>
<section>
<title>/etc/security/limits.conf</title>
<para>很多资料上是这么写的</para>
<screen>
<![CDATA[
* soft nofile 65535
* hard nofile 65535
]]>
</screen>
<para>这样做是偷懒,会带来很多问题,如果你的服务器被攻击,由于你的设置,系统将耗光你的资源,直到没有任何响应为止,你可能键盘输入都成问题,你不得不重启服务器,但你会发现重启只能维持短暂几分钟,又会陷入无响应状态。</para>
<screen>
<![CDATA[
nobody soft nofile 4096
nobody hard nofile 8192
]]>
</screen>
<para>为什么会设置为nobody用户呢?因为root用户启动系统后web 服务器会使用nobody用户创建子进程,socket连接实际上是nobody用户在处理。root 仅仅是守护父进程。</para>
<screen>
<![CDATA[
mysql soft nofile 2048
mysql hard nofile 2048
]]>
</screen>
<para>针对 mysql 做限制</para>
<tip>
<para>关于 nofile 即打开文件数,这个跟socket有非常紧密的关系,在linux系统中任何设备都被看做是一个文件(字符设备),你连接一个鼠标,键盘,摄像头,硬盘等等都被看作打开一个设备文件,所以默认1024是远远不够的。</para>
</tip>
<screen>
<![CDATA[
cat >> /etc/security/limits.conf <<EOF
root soft nofile 65536
root hard nofile 65536
www soft nofile 65536
www hard nofile 65536
mysql soft nofile 65536
mysql hard nofile 65536
EOF
]]>
</screen>
</section>
<section>
<title>/etc/sysctl.conf</title>
<para>内核参数调整</para>
<screen>
<![CDATA[
cat >> /etc/sysctl.conf <<EOF
net.ipv4.ip_local_port_range = 1024 65500
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 60
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 4096
EOF
]]>
</screen>
</section>
</section>
<section>
<title>关闭 SELINUX</title>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/os/selinux.sh | bash
]]>
</screen>
</section>
<section>
<title>关闭写磁盘I/O功能</title>
<para>对于某些文件没必要记录文件的访问时间,由其是在高并发的IO密集操作的环境下,通过两个参数可以实现noatime,nodiratime减少不必要的系统IO资源。</para>
<para>编辑/etc/fstab 添加 noatime,nodiratime 参数</para>
<screen>
<![CDATA[
/dev/sdb1 /www ext4 noatime,nodiratime 0 0
]]>
</screen>
<para>我一般分区规划是,/系统根分区,swap交换分区,/www数据分区,同时 禁止写入atime时间,因为/www频繁请求会影响IO </para>
<para>临时mount</para>
<screen>
<![CDATA[
mount -o remount,noatime,nodiratime /dev/sda3 /mnt/your
]]>
</screen>
<para>LABEL 方式</para>
<screen>
<![CDATA[
LABEL=/www /www ext3 defaults,noatime,nodiratime 1 1
]]>
</screen>
<para>UUID 方式</para>
<screen>
<![CDATA[
UUID=eeff3e86-7964-4a48-ac02-51ea167ea6b2 /www ext4 defaults,noatime,nodiratime 1 2
]]>
</screen>
<para>至此,Linux 的OS部分安装配置与优化完成。</para>
</section>
<section>
<title>放弃 LVM 使用 Btrfs</title>
<para>btrfa 的快照功能非常适合快速备份</para>
<para>子卷功能比物理分区更灵活</para>
<screen>
<![CDATA[
[root@netkiller ~]# cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Fri Nov 21 18:16:53 2014
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=6634633e-001d-43ba-8fab-202f1df93339 / ext4 defaults,barrier=0 1 1
UUID=786f570d-fe5c-4d5f-832a-c1b0963dd4e6 /srv btrfs defaults 1 1
UUID=786f570d-fe5c-4d5f-832a-c1b0963dd4e6 /var/lib/mongo btrfs noatime,nodiratime,subvol=@mongo 0 2
UUID=786f570d-fe5c-4d5f-832a-c1b0963dd4e6 /var/lib/mysql btrfs noatime,nodiratime,subvol=@mysql 0 2
UUID=786f570d-fe5c-4d5f-832a-c1b0963dd4e6 /www btrfs noatime,nodiratime,subvol=www 0 2
]]>
</screen>
</section>
<section id="openssh">
<title>Openssh 安全配置</title>
<para>这节主要讲与SSH有关的安全配置</para>
<section>
<title>禁止root用户登录</title>
<para>只允许普通用户登陆,然后通过su命令切换到root用过。后面还会将怎样限制su命令</para>
<screen>
<![CDATA[
PermitRootLogin no
]]>
</screen>
</section>
<section>
<title>限制SSH验证重试次数</title>
<para>超过3次socket连接会断开,效果不明显,有一点点用。</para>
<screen>
<![CDATA[
MaxAuthTries 3
]]>
</screen>
</section>
<section>
<title>禁止证书登陆</title>
<para>证书登陆非常安全,但是很有可能正常用户在你不知道情况下,给你安装了一个证书,他随时都可能进入你的系统</para>
<para>任何一个有权限的用户都能很方便的植入一个证书到 .ssh/authorized_keys 文件中</para>
<screen>
<![CDATA[
PubkeyAuthentication no
AuthorizedKeysFile /dev/null
]]>
</screen>
</section>
<section>
<title>使用证书替代密码认证</title>
<para>是不是自相矛盾? 这个跟上面讲的正好相反,这里只允许使用key文件登陆。</para>
<screen>
<![CDATA[
PasswordAuthentication no
]]>
</screen>
<para>这种方式比起密码要安全的多,唯一要注意的地方就是证书被拷贝 ,建议你给证书加上 passphrase。</para>
<para>证书的 passphrase 是可以通过openssl工具将其剥离的,SSH证书我没有试过,但是原理都差不多。</para>
</section>
<section>
<title>图形窗口客户端记忆密码的问题</title>
<para>当你使用XShell, Xftp, WinSCP, SecureCRT, SecureFX ......等等软件登录时,该软件都提供记住密码的功能,使你下次再登陆的时候无须输入密码就可以进入系统。这样做的确非常方便,</para>
<para>但是你是否想过你的电脑一旦丢失或者被其他人进入,那有多么危险。我之前每天背着笔记本电脑上班,上面安装着XShell并且密码全部记忆在里面。这使我意识到一点电脑丢失,有多么可怕。</para>
<para>禁止SSH客户端记住密码,你不要要求别人那么做。你也无法控制,最终我找到了一种解决方案。</para>
<screen>
<![CDATA[
ChallengeResponseAuthentication yes
]]>
</screen>
<para>每次登陆都回提示你输入密码。密码保存也无效。</para>
</section>
<section>
<title>关闭 GSSAPI</title>
<screen>
<![CDATA[
GSSAPIAuthentication no
#GSSAPIAuthentication yes
#GSSAPICleanupCredentials yes
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
]]>
</screen>
</section>
<section>
<title>禁止SSH端口映射</title>
<para>禁止使用SSH映射Socks5翻墙等等</para>
<screen>
<![CDATA[
AllowTcpForwarding no
]]>
</screen>
</section>
<section>
<title>IP地址限制</title>
<para>只允许通过192.168.2.1,192.168.2.2 访问本机</para>
<screen>
# vim /etc/hosts.allow
sshd:192.168.2.1,192.168.2.2
</screen>
<para>禁止所有人访问本机</para>
<screen>
# vim /etc/hosts.deny
sshd:ALL
</screen>
<para>上面使白名单策略,你也可以采用黑名单策略。</para>
</section>
<section>
<title>禁止SSH密码穷举</title>
<para>骇客常常使用骇客字典穷举你的SSH密码,使用下面脚本可以封杀频繁链接的IP地址</para>
<screen>
<![CDATA[
#!/bin/bash
########################################
# Homepage: http://netkiller.github.io
# Author: neo <[email protected]>
########################################
PIPE=/var/tmp/pipe
pidfile=/var/tmp/$0.pid
BLACKLIST=/var/tmp/black.lst
WHITELIST=/var/tmp/white.lst
LOGFILE=/var/log/secure
DAY=5
########################################
if [ -z "$( egrep "CentOS|7." /etc/centos-release)" ]; then
echo 'Only for CentOS 7.x'
exit
fi
if [ -f $BLACKLIST ]; then
find $BLACKLIST -type f -mtime +${DAY} -delete
fi
if [ ! -f ${BLACKLIST} ]; then
touch ${BLACKLIST}
fi
if [ ! -f ${WHITELIST} ]; then
touch ${WHITELIST}
fi
for ipaddr in $(grep rhost ${LOGFILE} | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" | sort | uniq -c | sort -r -n | head -n 10| awk '{print $2}')
do
if [ $(grep -c $ipaddr ${WHITELIST}) -gt 0 ]; then
continue
fi
if [ $(grep -c $ipaddr ${BLACKLIST}) -eq 0 ] ; then
echo $ipaddr >> ${BLACKLIST}
iptables -I INPUT -p tcp --dport 22 -s $ipaddr -j DROP
#iptables -I INPUT -s $ipaddr -j DROP
fi
done
]]>
</screen>
</section>
<section>
<title>解决 SSH 超时退出的问题</title>
<para>很多云主机 SSH 登录后,会自动断开。执行下面脚本可以解决。</para>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/os/ssh/config.sh | bash
]]>
</screen>
</section>
</section>
<section id="pam">
<title>PAM 插件认证加固配置</title>
<para>配置文件</para>
<screen>
<![CDATA[
ls /etc/pam.d/
chfn crond login passwd remote runuser-l smtp ssh-keycat sudo-i system-auth-ac
chsh fingerprint-auth newrole password-auth run_init smartcard-auth smtp.postfix su su-l
config-util fingerprint-auth-ac other password-auth-ac runuser smartcard-auth-ac sshd sudo system-auth
]]>
</screen>
<para>认证插件</para>
<screen>
<![CDATA[
ls /lib64/security/
]]>
</screen>
<section id="pam_tally2.so">
<title>pam_tally2.so</title>
<para>此模块的功能是,登陆错误输入密码3次,5分钟后自动解禁,在未解禁期间输入正确密码也无法登陆。</para>
<para>在配置文件 /etc/pam.d/sshd 顶端加入</para>
<screen>
<![CDATA[
auth required pam_tally2.so deny=3 onerr=fail unlock_time=300
]]>
</screen>
<para>查看失败次数</para>
<screen>
<![CDATA[
# pam_tally2
Login Failures Latest failure From
root 14 07/12/13 15:44:37 192.168.6.2
neo 8 07/12/13 15:45:36 192.168.6.2
]]>
</screen>
<para>重置计数器</para>
<screen>
<![CDATA[
# pam_tally2 -r -u root
Login Failures Latest failure From
root 14 07/12/13 15:44:37 192.168.6.2
# pam_tally2 -r -u neo
Login Failures Latest failure From
neo 8 07/12/13 15:45:36 192.168.6.2
]]>
</screen>
<para>pam_tally2 计数器日志保存在 /var/log/tallylog 注意,这是二进制格式的文件</para>
<example>
<title>/etc/pam.d/sshd - pam_tally2.so</title>
<screen>
<![CDATA[
# cat /etc/pam.d/sshd
#%PAM-1.0
auth required pam_tally2.so deny=3 onerr=fail unlock_time=300
auth required pam_sepermit.so
auth include password-auth
account required pam_nologin.so
account include password-auth
password include password-auth
# pam_selinux.so close should be the first session rule
session required pam_selinux.so close
session required pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session required pam_selinux.so open env_params
session optional pam_keyinit.so force revoke
session include password-auth
]]>
</screen>
</example>
<para>以上配置root用户不受限制, 如果需要限制root用户,参考下面</para>
<screen>
<![CDATA[
auth required pam_tally2.so deny=3 unlock_time=5 even_deny_root root_unlock_time=1800
]]>
</screen>
</section>
<section id="pam_listfile.so">
<title>pam_listfile.so</title>
<subtitle>用户登陆限制</subtitle>
<para>将下面一行添加到 /etc/pam.d/sshd 中,这里采用白名单方式,你也可以采用黑名单方式</para>
<screen>
<![CDATA[
auth required pam_listfile.so item=user sense=allow file=/etc/ssh/whitelist onerr=fail
]]>
</screen>
<para>将允许登陆的用户添加到 /etc/ssh/whitelist,除此之外的用户将不能通过ssh登陆到你的系统</para>
<screen>
<![CDATA[
# cat /etc/ssh/whitelist
neo
www
]]>
</screen>
<example>
<title>/etc/pam.d/sshd - pam_listfile.so</title>
<screen>
<![CDATA[
# cat /etc/pam.d/sshd
#%PAM-1.0
auth required pam_listfile.so item=user sense=allow file=/etc/ssh/whitelist onerr=fail
auth required pam_tally2.so deny=3 onerr=fail unlock_time=300
auth required pam_sepermit.so
auth include password-auth
account required pam_nologin.so
account include password-auth
password include password-auth
# pam_selinux.so close should be the first session rule
session required pam_selinux.so close
session required pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session required pam_selinux.so open env_params
session optional pam_keyinit.so force revoke
session include password-auth
]]>
</screen>
</example>
<para>sense=allow 白名单方式, sense=deny 黑名单方式</para>
<screen>
<![CDATA[
auth required pam_listfile.so item=user sense=deny file=/etc/ssh/blacklist onerr=fail
]]>
</screen>
<para>更多细节请查看手册 $ man pam_listfile</para>
</section>
<section id="pam_access.so">
<title>pam_access.so</title>
<para>编辑 /etc/pam.d/sshd 文件,加入下面一行</para>
<screen>
<![CDATA[
account required pam_access.so
]]>
</screen>
<para>保存后重启sshd进程</para>
<para>编辑 /etc/security/access.conf 文件</para>
<screen>
<![CDATA[
cat >> /etc/security/access.conf << EOF
- : root : ALL EXCEPT 192.168.6.1
EOF
]]>
</screen>
<para>只能通过 192.168.6.1 登陆, 添加多个IP地址</para>
<screen>
<![CDATA[
- : root : ALL EXCEPT 192.168.6.1 192.168.6.2
]]>
</screen>
<para>测试是否生效</para>
</section>
<section id="pam_wheel.so">
<title>pam_wheel.so</title>
<para>限制普通用户通过su命令提升权限至root. 只有属于wheel组的用户允许通过su切换到root用户</para>
<para>编辑 /etc/pam.d/su 文件,去掉下面的注释</para>
<screen>
<![CDATA[
auth required pam_wheel.so use_uid
]]>
</screen>
<para>修改用户组别,添加到wheel组</para>
<screen>
<![CDATA[
# usermod -G wheel www
# id www
uid=501(www) gid=501(www) groups=501(www),10(wheel)
]]>
</screen>
<para>没有加入到wheel组的用户使用su时会提示密码不正确。</para>
<screen>
<![CDATA[
$ su - root
Password:
su: incorrect password
]]>
</screen>
</section>
</section>
<section>
<title>NTP 服务</title>
<para>每个服务器必须安装 NTP,以保证服务器的时间准确。</para>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/os/ntpd/ntpdate.sh | bash
]]>
</screen>
</section>
</section>
<section id="jvm">
<title>Java 虚拟机</title>
<section>
<title>安装脚本</title>
<para>OpenJDK 1.8</para>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/lang/java/openjdk/java-1.8.0-openjdk.sh | bash
]]>
</screen>
<para>OpenJDK 11</para>
<screen>
<![CDATA[
curl -s https://raw.githubusercontent.com/oscm/shell/master/lang/java/openjdk/java-11-openjdk.sh | bash
]]>
</screen>
<para>Oracle Server JRE 1.8</para>
<para>http://java.oracle.com 下载 server-jre-8u212-linux-x64.tar.gz 然后运行下面安装脚本</para>
<screen>
<![CDATA[
#!/bin/bash
tar zxf server-jre-8u212-linux-x64.tar.gz*
mv jdk1.8.0_212 /srv/
ln -s /srv/jdk1.8.0_212 /srv/java
cat >> /etc/profile.d/java.sh <<'EOF'
export JAVA_HOME=/srv/java
export JAVA_OPTS="-server -Xms512m -Xmx8192m"
export CLASSPATH=$JAVA_HOME/lib:$JAVA_HOME/jre/lib:.
export PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin:
EOF
sed -i '117s/securerandom.source/#securerandom.source/' /srv/java/jre/lib/security/java.security
sed -i '117isecurerandom.source=file:/dev/./urandom' /srv/java/jre/lib/security/java.security
cat >> /etc/man.config <<EOF
MANPATH /srv/java/man
EOF
alternatives --install /usr/bin/java java /srv/jdk1.8.0_212/bin/java 100 \
--family java-1.8.0-server-jre \
--slave /usr/bin/javac javac /srv/jdk1.8.0_212/bin/javac
]]>
</screen>
<para>如果服务器上安装了多个 JAVA 版本,切换 JAVA 版本使用下面命令</para>
<screen>
<![CDATA[
alternatives --config java
]]>
</screen>
</section>
<section id="jre">
<title>使用 Server JRE 替代JDK。</title>
<para>服务器上不要安装JDK,请使用 Server JRE. 服务器上根本不需要编译器,代码应该在Release服务器上完成编译打包工作。</para>
<para>理由:一旦服务器被控制,可以防止在其服务器上编译其他恶意代码并植入到你的程序中。</para>
</section>
<section id="JAVA_OPTS">
<title>JAVA_OPTS</title>
<para>加入 -server 选项使 JRE 工作在服务器模式。</para>
<screen>
<![CDATA[
export JAVA_OPTS="-server -Xms512m -Xmx4096m -XX:PermSize=64M -XX:MaxPermSize=512m"
]]>
</screen>
<para>-Xms 指定初始化时化的栈内存</para>
<para>-Xmx 指定最大栈内存</para>
<tip>
<para>Java 8 以后 -XX:PermSize 与 -XX:MaxPermSize 两个配置项被废弃</para>
</tip>
<screen>
<![CDATA[
export JAVA_OPTS="-server -Xms512m -Xmx4096m"
]]>
</screen>
</section>
<section>
<title>java.security 优化</title>
<para></para>
<para>打开$JAVA_HOME/jre/lib/security/java.security文件,找到下面的内容:</para>
<screen>
<![CDATA[
securerandom.source=file:/dev/urandom
替换成
securerandom.source=file:/dev/./urandom
]]>
</screen>
</section>
<section>
<title>jconsole 配置</title>
<screen>
<![CDATA[
java -jar -Djava.rmi.server.hostname=192.168.0.1 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=911 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false netkiller-1.0-SNAPSHOT.jar
]]>
</screen>
<para>如果是云主机,配置 java.rmi.server.hostname=192.168.0.1 为内网IP地址,这样只能从内网监控 JVM</para>
<para>启动 jconsole</para>
<screen>
<![CDATA[
jconsole localhost:911
]]>
</screen>
</section>
</section>
<section id="springboot">
<title>配置 Spring boot</title>
<para>下面以 Springboot 2.0 为例。</para>
<section>
<title>指定配置文件</title>
<para>配置文件位置,默认application.properties是放在jar包中的,这样对于运维并不友好。通过spring.config.location可以制定外部配置文件,这样更便于运维。</para>
<para>--spring.config.location 指定配置文件</para>
<screen>
<![CDATA[
java -jar demo.jar --spring.config.location=/opt/config/application.properties
]]>
</screen>
<para>这样运维人员便于配置数据库链接,切换服务器等操作</para>
</section>
<section>
<title>日志文件</title>
<para>默认日志文件</para>
<screen>
<![CDATA[
logging.path=/tmp # 日志目录默认为 /tmp
logging.file=spring.log # 日志文件名称,默认为spring.log
]]>
</screen>
<para>需要需要根据每个服务器的情况来指定日志存储的目录</para>
<screen>
<![CDATA[
java -jar spring-boot-app.jar --logging.file=/tmp/spring-2018-12-10.log
]]>
</screen>
</section>
<section>
<title>如何启动 Springboot 程序</title>
<section>
<title>systemd</title>
<para>/etc/systemd/system/spring.service</para>
<screen>
<![CDATA[
####################################################
# Homepage: http://netkiller.github.io
# Author: netkiller<[email protected]>
# Script: https://github.com/oscm/shell
# Date: 2015-11-03
####################################################
[Unit]
Description=Spring Boot Application
After=network.target
[Service]
User=www
Group=www
Type=oneshot
WorkingDirectory=/www/netkiller.cn/api.netkiller.cn
ExecStart=/usr/bin/java -jar -Xms256m -Xmx4G -Dlog.level.console=warn your_jar_file.jar --spring.config.location=appliction-production.properties --spring.profiles.active=profile
#ExecStop=pkill -9 -f
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
]]>
</screen>
</section>
<section>
<title>传统 init.d 脚本</title>
<screen>
<![CDATA[
#!/bin/bash
##############################################
# Author: netkiller<[email protected]>
# Homepage: http://www.netkiller.cn
# Date: 2017-02-08
# $Author$
# $Id$
##############################################
# chkconfig: 345 100 02
# description: Spring boot application
# processname: springbootd
# File : springbootd
##############################################
BASEDIR="/www/netkiller.cn/api.netkiller.cn"
JAVA_HOME=/srv/java
JAVA_OPTS="-server -Xms2048m -Xmx8192m -Dlog.level.console=warn -Djava.security.egd=file:/dev/./urandom"
PACKAGE="api.netkiller.cn-0.0.2-release.jar"
CONFIG="--spring.config.location=$BASEDIR/application.properties"
USER=www
##############################################
NAME=springbootd
PROG="$JAVA_HOME/bin/java $JAVA_OPTS -jar $BASEDIR/$PACKAGE $CONFIG"
LOGFILE=/var/tmp/$NAME.log
PIDFILE=/var/tmp/$NAME.pid
ACCESS_LOG=/var/tmp/$NAME.access.log
##############################################
function log(){
echo "$(date -d "today" +"%Y-%m-%d %H:%M:%S") $1 $2" >> $LOGFILE
}
function start(){
if [ -f "$PIDFILE" ]; then
echo $PIDFILE
exit 2
fi
su - $USER -c "$PROG & echo \$! > $PIDFILE"
log info start
}
function stop(){
[ -f $PIDFILE ] && kill `cat $PIDFILE` && rm -rf $PIDFILE
log info stop
}
function status(){
ps aux | grep $PACKAGE | grep -v grep | grep -v status
log info status
}
function reset(){
pkill -f $PACKAGE
[ -f $PIDFILE ] && rm -rf $PIDFILE
log info reset
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
start
;;
log)
tail -f $LOGFILE
;;
reset)
reset
;;
*)
echo $"Usage: $0 {start|stop|status|restart|log|reset}"
esac
exit $?
]]>
</screen>
</section>
</section>
<section>
<title>监听端口</title>
<para>不要使用root用户启动springboot,Java程序与C程序不同。nginx,httpd 使用root用户启动守护80端口,子进程/线程会通过setuid(),setgid()两个函数切换到普通用户。即父进程所有者是root用户,子进程与多线程所有者是一个非root用户,这个用户没有shell权限,无法通过ssh与控制台登陆系统。</para>
<para>Java 的JVM 是与系统无关的,是建立在OS之上的,你使用什么用户启动Springboot,那麽Springboot 就会继承该所有者的权限。</para>
<para>一旦 springboot 被攻击,黑客将会获得 root 权限,控制整个系统。</para>
<screen>
<![CDATA[
server.port=8080 # 监听端口
]]>
</screen>
<para>服务器上有多个网卡的情况,需要指定一个网络适配器监听端口。</para>
<screen>
<![CDATA[
server.address=192.168.0.1 # 绑定的地址
]]>
</screen>
<section>
<title>使用 80 端口</title>
<para>Linux系统小于1024的端口只有root可以使用,这也是为什么Springboot默认端口是8080。如果你想使用80端口只能使用root启动Springboot,不建议这样做,这会带来了很多安全问题。建议使用iptables端口转发。</para>