Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ff5a2cf94 | ||
|
|
d46a8c86be | ||
|
|
6abfbb3570 | ||
|
|
b75db7fc5b | ||
|
|
501744a65f | ||
|
|
9a678b46e2 | ||
|
|
80c433478b | ||
|
|
498ccf2215 | ||
|
|
bf065f9b54 | ||
|
|
2d28ea551a | ||
|
|
71b0e00288 | ||
|
|
a1b63ac417 | ||
|
|
8af4363672 | ||
|
|
c2d1b1cc4a | ||
|
|
81755e32ec | ||
|
|
531322c6b3 | ||
|
|
e3f3254fe6 | ||
|
|
8bc1a4bcde | ||
|
|
467d06f4db | ||
|
|
4091355e18 | ||
|
|
6ef87be59b | ||
|
|
587396a5c9 | ||
|
|
45be5cbbef | ||
|
|
b3d842a1ba | ||
|
|
29102deadf | ||
|
|
68e27571fd | ||
|
|
681ed3e272 | ||
|
|
f6f85c765b | ||
|
|
b6c6bbe893 | ||
|
|
8e7100acaf | ||
|
|
42d2b3368b | ||
|
|
4d96993a18 | ||
|
|
1486e3090f | ||
|
|
a2eaa210f6 | ||
|
|
e8e642b010 | ||
|
|
1b50b85157 | ||
|
|
5f7bbd981b | ||
|
|
3cf4a88b93 | ||
|
|
5a2a72b582 | ||
|
|
01dd7b7b68 | ||
|
|
6b64369698 | ||
|
|
9448686168 | ||
|
|
01d7a8ac00 | ||
|
|
742b21c6a2 | ||
|
|
b90f091bb6 | ||
|
|
e3a6cb3774 | ||
|
|
7addced32c | ||
|
|
7e77350428 | ||
|
|
af0d548a07 | ||
|
|
3efa3b40c9 | ||
|
|
206322271c | ||
|
|
e5b9236268 | ||
|
|
c3b57bf6c7 | ||
|
|
652b65b3c2 | ||
|
|
41030320bb | ||
|
|
76c42c4799 | ||
|
|
65add73e70 | ||
|
|
a0000e1919 | ||
|
|
f9e2603b16 | ||
|
|
50d789fd42 | ||
|
|
25ab600eef | ||
|
|
be45519a22 | ||
|
|
ccaa384cd0 | ||
|
|
1c09ce9e09 | ||
|
|
fec00893b1 | ||
|
|
acadebe9fd | ||
|
|
a2ec025230 | ||
|
|
08682075c6 | ||
|
|
e3e790046f | ||
|
|
50319fb1b8 | ||
|
|
c3eb0811e0 | ||
|
|
5423449177 | ||
|
|
f713d43697 | ||
|
|
e896eec89f | ||
|
|
25a120ba65 | ||
|
|
3b865fcea8 | ||
|
|
f71ca999c9 | ||
|
|
276c168839 | ||
|
|
92f0b6e551 | ||
|
|
6b7d6ab301 | ||
|
|
6c33168378 | ||
|
|
8a8ac2d9b9 | ||
|
|
a59063bdb2 | ||
|
|
c597b162d9 | ||
|
|
322e6f7dcd | ||
|
|
c92819ca9d | ||
|
|
57d0ae3932 | ||
|
|
321bfa8f1f | ||
|
|
78838a606d | ||
|
|
fd16fb993d | ||
|
|
1841b7441d | ||
|
|
ce8786b9d2 | ||
|
|
82d366364f | ||
|
|
bd8b2962dc | ||
|
|
f2833f2c4e | ||
|
|
a4c0b0f555 | ||
|
|
a7e30075a9 | ||
|
|
861fd42d29 | ||
|
|
ef50fbbff6 | ||
|
|
f429f1922a | ||
|
|
06322dc8a4 | ||
|
|
afe718b621 | ||
|
|
5e4d6bd857 | ||
|
|
e61c50a6a1 | ||
|
|
b1e22ab47b | ||
|
|
986d47b5dd | ||
|
|
8c18e40024 | ||
|
|
f79d0ee3ee | ||
|
|
539fa088d1 | ||
|
|
ab7bb94b39 | ||
|
|
2aedaa9ba4 | ||
|
|
e91b9b8824 | ||
|
|
d695a2041e | ||
|
|
19d3af9056 | ||
|
|
31e9f22072 | ||
|
|
675eb15603 | ||
|
|
5e1f758943 | ||
|
|
a7aef2a595 | ||
|
|
fa2438248e | ||
|
|
6bebdb8e17 | ||
|
|
40fbe9cab0 | ||
|
|
be80d91a5c | ||
|
|
975b829f0a | ||
|
|
0e2212dcaa | ||
|
|
94e74e3d80 | ||
|
|
008a7cbe9f | ||
|
|
8584110e73 | ||
|
|
6d89e6bab6 | ||
|
|
1731febeb1 | ||
|
|
268f0e6811 | ||
|
|
e31f3f1b41 | ||
|
|
5acdc4a4b9 | ||
|
|
0f1d4cd952 | ||
|
|
c398f1043c | ||
|
|
091fa77d11 | ||
|
|
1b97f31edb | ||
|
|
8c454fa733 | ||
|
|
32c1150b28 | ||
|
|
19341205b7 | ||
|
|
89dfce5bbd | ||
|
|
a62389b85f | ||
|
|
5aa397ca22 | ||
|
|
d41ce88f16 | ||
|
|
310015ff53 | ||
|
|
bb7ba83362 | ||
|
|
c0d8eb6318 | ||
|
|
19bf91e13b | ||
|
|
9ae4f774e9 | ||
|
|
6c14d968c9 | ||
|
|
3e655d846b | ||
|
|
0232e31a50 | ||
|
|
a396f049d0 | ||
|
|
a55acdd372 | ||
|
|
ca3e46ebbd | ||
|
|
e661e9542d | ||
|
|
b923caf79e | ||
|
|
3e79863aa7 | ||
|
|
d172d8e18b | ||
|
|
38c410c5aa | ||
|
|
653eac6002 | ||
|
|
6c995eb04c | ||
|
|
e52f1e76e9 | ||
|
|
cf69099d3a | ||
|
|
20f1be3975 | ||
|
|
f602687c90 | ||
|
|
a3404a132d | ||
|
|
46836ccc4c | ||
|
|
ff8e66af07 | ||
|
|
01cc5fa642 | ||
|
|
cd47487b0b | ||
|
|
7e7e553c0d | ||
|
|
8385fd10e5 | ||
|
|
ccc795d58e | ||
|
|
0007b12080 | ||
|
|
2958b5cc07 | ||
|
|
0c5014489e | ||
|
|
ebf99869ff | ||
|
|
a43a0fe2f5 | ||
|
|
88b57f9f32 | ||
|
|
e028c34448 | ||
|
|
7c1ec6a762 | ||
|
|
fa6843ae61 | ||
|
|
76cc9e3296 | ||
|
|
6bcdb834ed | ||
|
|
2bac1c9ba9 | ||
|
|
0e6ca81f57 | ||
|
|
4bc2522e25 | ||
|
|
d4bb6239c7 | ||
|
|
082e9c0406 | ||
|
|
178742e0f3 | ||
|
|
1651aa7004 | ||
|
|
e6c9e4558e | ||
|
|
b6f1bdf098 | ||
|
|
cbc15ad069 | ||
|
|
68d295ec6b | ||
|
|
90339357c2 | ||
|
|
2e7368d011 | ||
|
|
6cd65fbed8 | ||
|
|
1ede736971 | ||
|
|
1935abd563 | ||
|
|
842ccf4853 | ||
|
|
2c56a313a1 | ||
|
|
7b00d73a6f | ||
|
|
a995e7e724 | ||
|
|
3211d6d25d | ||
|
|
d011bb454a | ||
|
|
8e62436697 | ||
|
|
c9811171ce | ||
|
|
30eebaf16a | ||
|
|
dbf001fa53 | ||
|
|
f753fc91f2 | ||
|
|
239a321588 | ||
|
|
61eb1f95a4 | ||
|
|
a66a6b89da | ||
|
|
46923d0a0a | ||
|
|
ba1b4d5db9 | ||
|
|
ba0a25acf9 | ||
|
|
371e30fe3d | ||
|
|
1013834e3c | ||
|
|
e802c28801 | ||
|
|
14d503580b | ||
|
|
0fc109c199 | ||
|
|
63fd576d3e | ||
|
|
f0c8ee256e | ||
|
|
d5cb68084e | ||
|
|
f7d2309608 | ||
|
|
d800e8d629 | ||
|
|
eebc9537a2 | ||
|
|
1fed099b53 | ||
|
|
25dfae1fea | ||
|
|
c365fb08cf | ||
|
|
768b715fdf | ||
|
|
7d938ac405 | ||
|
|
2f5964519a | ||
|
|
2064384985 | ||
|
|
b436699260 | ||
|
|
1a025da649 | ||
|
|
4c3d0e0603 | ||
|
|
714b7bfbba | ||
|
|
16ffe1e1c4 | ||
|
|
7f1c143d77 | ||
|
|
f42af35352 | ||
|
|
8bbe13b6fa | ||
|
|
dea7143827 | ||
|
|
41d5f72822 | ||
|
|
3e49a3af98 | ||
|
|
89ff4a6d53 | ||
|
|
a5852f3003 | ||
|
|
4a04999ce7 | ||
|
|
c16aac808f | ||
|
|
0aa173789a | ||
|
|
38b5cd8193 | ||
|
|
ef59f7c26e | ||
|
|
08900887e4 | ||
|
|
9ddbe5a329 | ||
|
|
3f7fccf5f1 | ||
|
|
d9e148c0f2 | ||
|
|
613c4b9ea1 | ||
|
|
fe0060af77 | ||
|
|
7b428fe230 | ||
|
|
2e148546d8 | ||
|
|
23d76594a6 | ||
|
|
512a5f2886 | ||
|
|
09d5fdcd1e | ||
|
|
e4d6fb9b61 | ||
|
|
c11b839009 | ||
|
|
6cda7cd7d5 | ||
|
|
381c24e940 | ||
|
|
a8e901639e | ||
|
|
93a80e44d3 | ||
|
|
bc866a4d18 | ||
|
|
ec557f7ce8 | ||
|
|
4cee8b7e35 | ||
|
|
ba53a2b8ab | ||
|
|
3a8655de81 | ||
|
|
3f62126bdd | ||
|
|
ee8768591b | ||
|
|
6e93b799b1 | ||
|
|
17d19cacff | ||
|
|
f5a1ad61bd | ||
|
|
8840f0dc5b | ||
|
|
5ab9f0b251 | ||
|
|
a540a7359a | ||
|
|
fc368485ef | ||
|
|
8f510a1b67 | ||
|
|
9d68ee2359 | ||
|
|
ef4f5aeaeb | ||
|
|
a79260a324 | ||
|
|
0c398d21f2 | ||
|
|
f1957631b5 | ||
|
|
86b3ab5186 | ||
|
|
a1c131f922 | ||
|
|
54aacb786f | ||
|
|
564803c9f8 | ||
|
|
f421d7e5a8 | ||
|
|
5f793beb73 | ||
|
|
5fd9e01493 | ||
|
|
a4e45a0e95 | ||
|
|
dd2976794a | ||
|
|
edf28c8790 | ||
|
|
7c98598858 | ||
|
|
2393f0bbf9 | ||
|
|
4e044602f4 | ||
|
|
fdd30717e5 | ||
|
|
272e06bbec | ||
|
|
e57668fc75 | ||
|
|
9dd7f0947a | ||
|
|
ca6e4b43e4 | ||
|
|
3a2fb3584b | ||
|
|
550447234a | ||
|
|
717d9b2630 | ||
|
|
6b7ccdadc4 | ||
|
|
b511abab60 | ||
|
|
fab5cb9a21 | ||
|
|
949eb9e04a | ||
|
|
e4656bcae8 | ||
|
|
f62454df8d | ||
|
|
7374d8b5dd | ||
|
|
99b9c0af27 | ||
|
|
fbff67c7eb | ||
|
|
6fc1ee0adb | ||
|
|
2bf5a195c1 | ||
|
|
2d326419c2 | ||
|
|
31fc0ab6d9 | ||
|
|
7e2bd017b3 | ||
|
|
5d6446afed | ||
|
|
b1ead662a2 | ||
|
|
bf9173acea | ||
|
|
568a79b4f6 | ||
|
|
e64fb4cdbd | ||
|
|
2b77ac2b1e | ||
|
|
20ea63ebe5 | ||
|
|
11d5200962 | ||
|
|
aefad52704 | ||
|
|
86b856a88c | ||
|
|
33dcb3f267 | ||
|
|
7c9ab1395f | ||
|
|
1a8fb44b78 | ||
|
|
51d91c7d2e | ||
|
|
0cd0d83172 | ||
|
|
b3f1b3b478 | ||
|
|
4ff34de49b | ||
|
|
5bce1db05e | ||
|
|
b27f619d5e | ||
|
|
9cce9fcec7 | ||
|
|
f05d3caa0b | ||
|
|
3c1533790f | ||
|
|
20746518bc | ||
|
|
75808b1dc1 | ||
|
|
7c9f01639b | ||
|
|
6cb9999864 | ||
|
|
a621249787 | ||
|
|
679f135b62 | ||
|
|
5c456ddb86 | ||
|
|
c1c07bcea2 | ||
|
|
c703aa4039 | ||
|
|
1051bc5922 | ||
|
|
155299a8d5 | ||
|
|
f0b63e3cb6 | ||
|
|
479ab1dae6 | ||
|
|
b5058cd906 | ||
|
|
c1115e556b | ||
|
|
617d3d28b5 | ||
|
|
582a631014 | ||
|
|
f4c2ae451f | ||
|
|
b76b2c3df4 | ||
|
|
0bbf43146c | ||
|
|
c33452bba0 | ||
|
|
300c8d9d94 | ||
|
|
7b1f046586 | ||
|
|
4e290e192d | ||
|
|
8d562f2490 | ||
|
|
47150155a0 | ||
|
|
b3d323d742 | ||
|
|
6060cf243f | ||
|
|
e044a540ed | ||
|
|
f6a4bffe88 | ||
|
|
343e24886d | ||
|
|
997d4bfb2b | ||
|
|
9ded3269c6 | ||
|
|
ca65a446bd | ||
|
|
4e9aa21cea | ||
|
|
ed014ecf8e | ||
|
|
2e11c04664 | ||
|
|
80662bd203 | ||
|
|
5705f81911 | ||
|
|
b4e3d40f4b | ||
|
|
cea0ca7fa8 | ||
|
|
69bed16e4f | ||
|
|
5b173cf4a7 | ||
|
|
0a0720a26c | ||
|
|
fa3504c350 | ||
|
|
4020000d68 | ||
|
|
ab7eeccfb0 | ||
|
|
78a16fa0ea | ||
|
|
b26c4be8d6 | ||
|
|
aada33f0e9 | ||
|
|
7b88c48a6e | ||
|
|
ded260ee19 | ||
|
|
3e9c270ac7 | ||
|
|
bf6e41566d | ||
|
|
ededabf00f | ||
|
|
3df9d35c57 | ||
|
|
a90c3b0f12 | ||
|
|
d19b0769b4 | ||
|
|
97f25cd7d1 | ||
|
|
03331147ca | ||
|
|
d44138bead | ||
|
|
eb21b030c2 | ||
|
|
3061756a55 | ||
|
|
2964280976 | ||
|
|
f657071a7f | ||
|
|
2cdc4775e0 | ||
|
|
af5b86e28c | ||
|
|
1021f6b1d7 | ||
|
|
0111b7ec2b | ||
|
|
33524757aa | ||
|
|
eea4a8e2c3 | ||
|
|
fb98d3112d | ||
|
|
97c81ccf60 | ||
|
|
e9b79fbdd4 | ||
|
|
217e3563d6 | ||
|
|
deb33bb05f | ||
|
|
e605eef755 | ||
|
|
c304036f97 | ||
|
|
c1061b50e0 | ||
|
|
3b07496a4d | ||
|
|
3eb2b6e2c9 | ||
|
|
5f5da069fd | ||
|
|
ceeffb97a0 | ||
|
|
27faab919c | ||
|
|
f4fc7c1b5d | ||
|
|
54d796b1f3 | ||
|
|
9065e3b2ae | ||
|
|
bd14ab8bc1 | ||
|
|
2ac6a2b540 | ||
|
|
9d81c393de | ||
|
|
b557786325 | ||
|
|
5572bb8118 | ||
|
|
ac9412920f | ||
|
|
d50d9c81f8 | ||
|
|
de98d9fbeb | ||
|
|
eac15d6258 | ||
|
|
0c671d0f62 | ||
|
|
e9064dfddc | ||
|
|
cf10a9617f | ||
|
|
c571b97bc9 | ||
|
|
fa5954c9ce | ||
|
|
58ec098c05 | ||
|
|
c9211b9e56 | ||
|
|
a3e9939f76 | ||
|
|
450d065f55 | ||
|
|
9ce3c06d5c | ||
|
|
ee951c8460 | ||
|
|
69621f7034 | ||
|
|
4cf3d15af0 | ||
|
|
5d875a225c | ||
|
|
6792fba91f | ||
|
|
f559f3328b | ||
|
|
38e512291d | ||
|
|
cfc0d213cd | ||
|
|
22125549a6 | ||
|
|
9e8378aece | ||
|
|
79603c8cf7 | ||
|
|
c21163aadc | ||
|
|
c03ecbde4a | ||
|
|
57f3a8b911 | ||
|
|
37660e0fe9 | ||
|
|
dcf02b9549 | ||
|
|
3c46f405a9 | ||
|
|
94548d0dcf | ||
|
|
1497c9a872 | ||
|
|
a5828a2d3b | ||
|
|
5769acf820 | ||
|
|
aa0658b5ac | ||
|
|
49dbd1d33b | ||
|
|
68fe23018a | ||
|
|
ea9db7e273 | ||
|
|
56ba00f524 | ||
|
|
d18bf855cb | ||
|
|
cbe1f104da | ||
|
|
6eb12b3bfe | ||
|
|
98533bc11a | ||
|
|
e4b8992301 | ||
|
|
ee2ccb0c26 | ||
|
|
61ecb69ab1 | ||
|
|
c43ace22a3 | ||
|
|
fb0d7c5d82 | ||
|
|
403d424d66 | ||
|
|
760e57c520 | ||
|
|
72b8bfa8f6 | ||
|
|
8c769e445c | ||
|
|
3c685279be | ||
|
|
7fdebfc4db | ||
|
|
0d3fe6130a | ||
|
|
bb34be7e02 | ||
|
|
fe55216e2a | ||
|
|
3191f087bb | ||
|
|
e80311d937 | ||
|
|
d4717302d4 | ||
|
|
a5d54af2b8 | ||
|
|
1b2a930a9c | ||
|
|
33d4192871 | ||
|
|
2a0ed94d0d | ||
|
|
9ff5d5a70e | ||
|
|
6a1cee846a | ||
|
|
cd002d0aff | ||
|
|
d2bb2f126b | ||
|
|
ec4e755f2f | ||
|
|
3e9193af7f | ||
|
|
efd0ec85b9 | ||
|
|
c036c91247 | ||
|
|
dad526245d | ||
|
|
c591765f70 | ||
|
|
51f3eaa3f0 | ||
|
|
574a1483eb | ||
|
|
a0604ba3a5 | ||
|
|
0da4ea69bf | ||
|
|
6213291be8 | ||
|
|
619e17d7a1 | ||
|
|
c64ba4bf91 | ||
|
|
44572936ec | ||
|
|
9c9e58c23d | ||
|
|
b9d6a1ea85 | ||
|
|
4c345f3799 | ||
|
|
6009ee67fa | ||
|
|
ddbf2e8c11 | ||
|
|
edaea49cd0 | ||
|
|
54727d933d | ||
|
|
3e1cc3c9e9 | ||
|
|
1cae69d080 | ||
|
|
6f8028fc17 | ||
|
|
d507039d5f | ||
|
|
b5ac0bc5d6 | ||
|
|
31de106ba8 | ||
|
|
aaa54cc401 | ||
|
|
51d639e2ef | ||
|
|
330d7f0516 | ||
|
|
73c4923334 | ||
|
|
10fdf4ef33 | ||
|
|
ed48daa092 | ||
|
|
7f71a352a7 | ||
|
|
ba412ab407 | ||
|
|
7b0817202c | ||
|
|
36876072f2 | ||
|
|
b7b5c43cdf | ||
|
|
100b4e8b9e | ||
|
|
e873a40cc3 | ||
|
|
1d9968b3af | ||
|
|
6338c53c2e | ||
|
|
0c70bacf4f | ||
|
|
56bba70ef3 | ||
|
|
03cc3fb1bd | ||
|
|
bcc1cc5384 | ||
|
|
5ef97ae896 | ||
|
|
dfa34e1880 | ||
|
|
542694841a | ||
|
|
e6a44c6ff8 | ||
|
|
7637108234 | ||
|
|
23bf4c81b0 | ||
|
|
090700f641 | ||
|
|
e129ba6971 | ||
|
|
51cd3523fc | ||
|
|
ac501a20d2 | ||
|
|
83a7448c99 | ||
|
|
d228acfe71 | ||
|
|
49c540e993 | ||
|
|
9f7caabef4 | ||
|
|
2770be643f | ||
|
|
5cd52242c4 | ||
|
|
6b4227da4d | ||
|
|
2e1aa0db4a | ||
|
|
e7baeac2e5 | ||
|
|
051319fab7 | ||
|
|
917e630697 | ||
|
|
68166559c5 | ||
|
|
fee55ba7f8 | ||
|
|
d0e0009efc | ||
|
|
57ff1d5c06 | ||
|
|
f0834d30a2 | ||
|
|
4d82220212 | ||
|
|
f8d5ce70cf | ||
|
|
5f060801ef | ||
|
|
04da47d83e | ||
|
|
5efa416ea9 | ||
|
|
7b0fe81d01 | ||
|
|
1067255173 | ||
|
|
7cc0be4188 | ||
|
|
b0035158d2 | ||
|
|
7070eb724c | ||
|
|
f7dccc079b | ||
|
|
6c588848ef | ||
|
|
ad3a8e6748 | ||
|
|
3fa627a2cd | ||
|
|
30b49c4d7b | ||
|
|
f2c5752718 | ||
|
|
d0dc7f4b0e | ||
|
|
3304285b4e | ||
|
|
d80d326f7c | ||
|
|
df48615a26 | ||
|
|
59785196d4 | ||
|
|
02252c690d | ||
|
|
25be9e41dd | ||
|
|
ddf815d636 | ||
|
|
95c04b1e9d | ||
|
|
0f2e5e0def | ||
|
|
8b20fd9dcf | ||
|
|
d4e3258d53 | ||
|
|
b4e3f78b72 | ||
|
|
20257cd917 | ||
|
|
317dfcefd2 | ||
|
|
42e8666356 | ||
|
|
49a419548f | ||
|
|
790607c6c0 | ||
|
|
91378c3d92 | ||
|
|
207297c11d | ||
|
|
0d86096f09 | ||
|
|
67ab987f7e | ||
|
|
97457d71c0 | ||
|
|
1159a380ba | ||
|
|
ca6aa76729 | ||
|
|
7ce71f1632 | ||
|
|
98b47e0aeb | ||
|
|
159c165468 | ||
|
|
4eeabb2c7f | ||
|
|
7e35b03452 | ||
|
|
c8e4f766a2 | ||
|
|
0ee39a4470 | ||
|
|
fc7c913122 | ||
|
|
3e15586597 | ||
|
|
3d07ce8004 | ||
|
|
22ab851681 | ||
|
|
152c876067 | ||
|
|
c10b2e0e55 | ||
|
|
2b15f11d57 | ||
|
|
b172f61c5f | ||
|
|
150b812371 | ||
|
|
434b1f604f | ||
|
|
6e3ab067d7 | ||
|
|
2e44d151fe | ||
|
|
c91a85a08a | ||
|
|
f8bb171209 | ||
|
|
f860c34d62 | ||
|
|
b8422a93b7 | ||
|
|
15b14555a6 | ||
|
|
467ab945cd | ||
|
|
dddeeb3332 | ||
|
|
f03f97ab07 | ||
|
|
75f70352ba | ||
|
|
4aa360a933 | ||
|
|
dce24a0a34 | ||
|
|
fae7a9fc17 | ||
|
|
79b0a00d5c | ||
|
|
e4fe5ab085 | ||
|
|
2049698c8e | ||
|
|
20bd32afb6 | ||
|
|
c132f7ee51 | ||
|
|
10025764cd | ||
|
|
c8c0e07a22 | ||
|
|
b55f4717b1 | ||
|
|
f493c380fc | ||
|
|
baa652197a | ||
|
|
a6525fc807 | ||
|
|
e01c39230a | ||
|
|
7b8b5fee4d | ||
|
|
819b77ae1a | ||
|
|
edccf88ccd | ||
|
|
7f42841572 | ||
|
|
b5a180d3de | ||
|
|
69efa2a0a3 | ||
|
|
7f4029386d | ||
|
|
9f7ed8214e | ||
|
|
5e67812d5a | ||
|
|
821de5fa8f | ||
|
|
20bf86ec12 | ||
|
|
87370a4fbc | ||
|
|
7b0e0e7f15 | ||
|
|
962494e47a | ||
|
|
c816e60441 | ||
|
|
d46fd6215a | ||
|
|
7bcd01e6be | ||
|
|
20a6028145 | ||
|
|
f784c48217 | ||
|
|
9b755b8b93 | ||
|
|
29261ed8bf | ||
|
|
1b5557d6ed | ||
|
|
3fd3c04429 | ||
|
|
5b9257b4ce | ||
|
|
d8d0783f29 | ||
|
|
4c7429efbc | ||
|
|
73727bd9d8 | ||
|
|
41e64f7405 | ||
|
|
50d32b9b4c | ||
|
|
ebfb4ea9a1 | ||
|
|
e030b61705 | ||
|
|
b32a7afa77 | ||
|
|
30ff6e6667 | ||
|
|
6fa27eed76 | ||
|
|
538b1fba1c | ||
|
|
d569605d0d | ||
|
|
ca4b45451f | ||
|
|
1d6248180e | ||
|
|
7cfa13f285 | ||
|
|
0bd8f8f507 | ||
|
|
62b914d743 | ||
|
|
65c0f07284 | ||
|
|
e3c0d53df5 | ||
|
|
8ad223f6f7 | ||
|
|
ac44416d0f | ||
|
|
3c72515946 |
@@ -0,0 +1,10 @@
|
||||
DOCKERFILE='Dockerfile'
|
||||
|
||||
EXTERNAL_REGISTRY_BASE_DOMAIN=quay.io
|
||||
REPOSITORY_NAME=fairwinds/polaris
|
||||
DOCKERTAG=${EXTERNAL_REGISTRY_BASE_DOMAIN}/${REPOSITORY_NAME}
|
||||
if [[ -n $CI_TAG ]]; then
|
||||
ADDITIONAL_DOCKER_TAG_VERSIONS=()
|
||||
ADDITIONAL_DOCKER_TAG_VERSIONS+=(`echo $CI_TAG | sed -e 's/\(\w\+\)\..*$/\1/'`)
|
||||
ADDITIONAL_DOCKER_TAG_VERSIONS+=(`echo $CI_TAG | sed -e 's/\(\w\+\.\w\+\)\..*$/\1/'`)
|
||||
fi
|
||||
@@ -1,137 +1,186 @@
|
||||
version: 2
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
rok8s: fairwinds/rok8s-scripts@11
|
||||
oss-docs: fairwinds/oss-docs@0
|
||||
|
||||
executors:
|
||||
vm:
|
||||
machine:
|
||||
enabled: true
|
||||
|
||||
commands:
|
||||
install_goreleaser_dependencies:
|
||||
description: Installs dependencies for CI scripts
|
||||
steps:
|
||||
- run: apk update
|
||||
# gettext provides envsubst
|
||||
- run: apk add gettext
|
||||
# Register other docker platforms, to build arm64.
|
||||
# This shouldn't be needed, why TBD.
|
||||
- run: docker run --privileged --rm tonistiigi/binfmt --install all
|
||||
|
||||
references:
|
||||
install_goreleaser: &install_goreleaser
|
||||
run:
|
||||
name: Install GoReleaser
|
||||
command: |
|
||||
curl -fsSLo goreleaser.deb https://github.com/goreleaser/goreleaser/releases/download/v0.94.0/goreleaser_amd64.deb
|
||||
echo "8dbad6683d6fc9367e637e6eed8e01a0d63c9660 goreleaser.deb" | sha1sum -c
|
||||
sudo dpkg -i goreleaser.deb
|
||||
rm goreleaser.deb
|
||||
set_environment_variables: &set_environment_variables
|
||||
run:
|
||||
name: Set Environment Variables
|
||||
command: |
|
||||
echo 'export REPO=quay.io/reactiveops/polaris' >> ${BASH_ENV}
|
||||
docker_build_and_push: &docker_build_and_push
|
||||
run:
|
||||
name: Docker login, build, and push
|
||||
command: |
|
||||
docker login quay.io -u="reactiveops+circleci" -p="${quay_token}"
|
||||
docker build -t $REPO:dev-$CIRCLE_SHA1 .
|
||||
docker push $REPO:dev-$CIRCLE_SHA1
|
||||
docker_tag_release: &docker_tag_release
|
||||
run:
|
||||
name: Docker tag release
|
||||
command: |
|
||||
docker login quay.io -u="reactiveops+circleci" -p="${quay_token}"
|
||||
docker pull $REPO:dev-$CIRCLE_SHA1
|
||||
docker tag $REPO:dev-$CIRCLE_SHA1 $REPO:$CIRCLE_TAG
|
||||
docker push $REPO:$CIRCLE_TAG
|
||||
echo 'export CI_SHA1=$CIRCLE_SHA1' >> ${BASH_ENV}
|
||||
echo 'export CI_BRANCH=$CIRCLE_BRANCH' >> ${BASH_ENV}
|
||||
echo 'export CI_BUILD_NUM=$CIRCLE_BUILD_NUM' >> ${BASH_ENV}
|
||||
echo 'export CI_TAG=$CIRCLE_TAG' >> ${BASH_ENV}
|
||||
echo 'export PUSH_ALL_VERSION_TAGS=true' >> ${BASH_ENV}
|
||||
echo 'export GOPROXY=https://proxy.golang.org' >> ${BASH_ENV}
|
||||
echo 'export GO111MODULE=on' >> ${BASH_ENV}
|
||||
echo 'export GOFLAGS=-mod=mod' >> ${BASH_ENV}
|
||||
echo 'export GORELEASER_CURRENT_TAG="${CIRCLE_TAG}"' >> $BASH_ENV
|
||||
|
||||
update_coverage: &update_coverage
|
||||
install_k8s: &install_k8s
|
||||
run:
|
||||
name: Update Coverage
|
||||
name: Install K8s
|
||||
command: |
|
||||
go test ./pkg/... -coverprofile=coverage.txt -covermode=count
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
sudo apt-get update
|
||||
echo "Installing git and jq"
|
||||
sudo apt-get install -yqq jq git
|
||||
|
||||
test_dashboard: &test_dashboard
|
||||
echo "Installing KIND"
|
||||
curl -sLO https://github.com/kubernetes-sigs/kind/releases/download/v0.14.0/kind-linux-amd64
|
||||
chmod 0755 kind-linux-amd64
|
||||
sudo mv kind-linux-amd64 /usr/local/bin/kind
|
||||
kind version
|
||||
|
||||
echo "Installing Kubectl"
|
||||
curl -sLO https://storage.googleapis.com/kubernetes-release/release/v1.21.12/bin/linux/amd64/kubectl
|
||||
chmod 0755 kubectl
|
||||
sudo mv kubectl /usr/local/bin/
|
||||
kubectl version --client
|
||||
|
||||
|
||||
echo "Creating Kubernetes Cluster with Kind"
|
||||
kind create cluster --wait=90s --image kindest/node:v1.21.12
|
||||
docker ps -a
|
||||
|
||||
kubectl version
|
||||
|
||||
echo "Installing Helm"
|
||||
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
|
||||
chmod 700 get_helm.sh
|
||||
./get_helm.sh
|
||||
|
||||
echo "Installing cert-manager"
|
||||
kubectl create namespace cert-manager
|
||||
helm repo add jetstack https://charts.jetstack.io
|
||||
helm repo update
|
||||
echo "Helm install"
|
||||
helm install cert-manager jetstack/cert-manager --namespace cert-manager --version 0.16.1 --set "installCRDs=true" --wait
|
||||
echo "Install cert-manager successful"
|
||||
|
||||
test_binary_dashboard: &test_binary_dashboard
|
||||
run:
|
||||
name: Test Dashboard
|
||||
command: |
|
||||
go run main.go --dashboard --dashboard-port 3000 --audit-path ./deploy/dashboard.yaml &
|
||||
sleep 5
|
||||
go run main.go dashboard --port 3000 --audit-path ./examples &
|
||||
sleep 30
|
||||
curl -f http://localhost:3000 > /dev/null
|
||||
curl -f http://localhost:3000/health > /dev/null
|
||||
curl -f http://localhost:3000/favicon.ico > /dev/null
|
||||
curl -f http://localhost:3000/static/css/main.css > /dev/null
|
||||
curl -f http://localhost:3000/results.json > /dev/null
|
||||
curl -f http://localhost:3000/details/security > /dev/null
|
||||
test_k8s: &test_k8s
|
||||
run:
|
||||
name: Test Kubernetes Deployments
|
||||
command: |
|
||||
if [[ -z $CIRCLE_PR_NUMBER ]]; then
|
||||
./test/webhook_test.sh
|
||||
./test/kube_dashboard_test.sh
|
||||
else
|
||||
echo "Skipping Kubernetes tests for forked PR"
|
||||
fi
|
||||
|
||||
install_vault_alpine: &install_vault_alpine
|
||||
run:
|
||||
name: install hashicorp vault
|
||||
command: |
|
||||
apk --update add curl yq
|
||||
cd /tmp
|
||||
curl -LO https://releases.hashicorp.com/vault/1.9.3/vault_1.9.3_linux_amd64.zip
|
||||
unzip vault_1.9.3_linux_amd64.zip
|
||||
mv vault /usr/bin/vault
|
||||
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: quay.io/reactiveops/ci-images:v8.0-stretch
|
||||
test_k8s:
|
||||
working_directory: ~/polaris
|
||||
resource_class: medium
|
||||
executor: vm
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker
|
||||
- *set_environment_variables
|
||||
- *docker_build_and_push
|
||||
- *install_k8s
|
||||
- *test_k8s
|
||||
|
||||
test:
|
||||
working_directory: /go/src/github.com/reactiveops/polaris/
|
||||
docker:
|
||||
- image: circleci/golang:1.12
|
||||
|
||||
- image: cimg/go:1.19
|
||||
steps:
|
||||
- checkout
|
||||
- run: go get -u golang.org/x/lint/golint
|
||||
- run: go list ./... | grep -v vendor | xargs golint -set_exit_status
|
||||
- run: go list ./... | grep -v vendor | xargs go vet
|
||||
- *update_coverage
|
||||
- *test_dashboard
|
||||
|
||||
test-deploy:
|
||||
docker:
|
||||
- image: quay.io/reactiveops/ci-images:v8.0-stretch
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Verify helm chart synced with dashboard.yaml
|
||||
command: |
|
||||
diff \
|
||||
<(helm template deploy/helm/polaris/ --name polaris --namespace polaris --set templateOnly=true) \
|
||||
deploy/dashboard.yaml || (echo "
|
||||
Make sure to regenerate k8s deploy config with make helm-to-k8s" &&
|
||||
exit 1)
|
||||
|
||||
- run:
|
||||
name: Verify helm chart synced with webhook.yaml
|
||||
command: |
|
||||
diff \
|
||||
<(helm template deploy/helm/polaris/ --name polaris --namespace polaris --set templateOnly=true --set webhook.enable=true --set dashboard.enable=false) \
|
||||
deploy/webhook.yaml || (echo "
|
||||
Make sure to regenerate k8s deploy config with make helm-to-k8s" &&
|
||||
exit 1)
|
||||
|
||||
release:
|
||||
working_directory: /go/src/github.com/reactiveops/polaris/
|
||||
docker:
|
||||
- image: circleci/golang:1.12
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker
|
||||
- *set_environment_variables
|
||||
- *docker_tag_release
|
||||
- *install_goreleaser
|
||||
- run: go get -u github.com/gobuffalo/packr/v2/packr2
|
||||
- run: packr2
|
||||
- run: goreleaser
|
||||
- run: go vet ./...
|
||||
- run: go test ./... -coverprofile=coverage.txt -covermode=count
|
||||
- *test_binary_dashboard
|
||||
|
||||
build_and_push:
|
||||
working_directory: /go/src/github.com/fairwindsops/polaris/
|
||||
resource_class: large
|
||||
shell: /bin/bash
|
||||
docker:
|
||||
# The goreleaser image tag determins the version of Go.
|
||||
# Manually check goreleaser images for their version of Go.
|
||||
# Ref: https://hub.docker.com/r/goreleaser/goreleaser/tags
|
||||
- image: goreleaser/goreleaser:v1.11.4
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker:
|
||||
version: 20.10.11
|
||||
- *install_vault_alpine
|
||||
- rok8s/get_vault_env:
|
||||
vault_path: repo/global/env
|
||||
- rok8s/get_vault_env:
|
||||
vault_path: repo/polaris/env
|
||||
- *set_environment_variables
|
||||
- run: docker login quay.io -u="${FAIRWINDS_QUAY_USER}" -p="${FAIRWINDS_QUAY_TOKEN}"
|
||||
- install_goreleaser_dependencies
|
||||
- run: scripts/goreleaser.sh
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build:
|
||||
jobs:
|
||||
- test
|
||||
- test-deploy
|
||||
- build:
|
||||
requires:
|
||||
- test
|
||||
- test-deploy
|
||||
context: org-global
|
||||
# Allow using testing tags for testing circle test + build steps
|
||||
filters:
|
||||
tags:
|
||||
only: /^testing-.*/
|
||||
|
||||
release:
|
||||
jobs:
|
||||
- release:
|
||||
- test:
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
- build_and_push:
|
||||
context: org-global
|
||||
requires:
|
||||
- test
|
||||
filters:
|
||||
branches:
|
||||
ignore: /pull\/[0-9]+/
|
||||
tags:
|
||||
ignore: /^testing-.*/
|
||||
- test_k8s:
|
||||
requires:
|
||||
- build_and_push
|
||||
filters:
|
||||
branches:
|
||||
ignore: /pull\/[0-9]+/
|
||||
tags:
|
||||
ignore: /^testing-.*/
|
||||
- oss-docs/publish-docs:
|
||||
repository: polaris
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
# Testing tags are reserved for testing circle test + build steps
|
||||
tags:
|
||||
ignore: /^testing-.*/
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
deploy
|
||||
examples
|
||||
.gitignore
|
||||
.git/*
|
||||
Dockerfile
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
name: Bug Report
|
||||
description: File a bug report
|
||||
labels: [bug, triage]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report! Please fill the form below.
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: What happened?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: What did you expect to happen?
|
||||
description: What is the expected or desired behavior?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproducible
|
||||
attributes:
|
||||
label: How can we reproduce this?
|
||||
description: Please share the steps that we can take to reproduce this. Also include any relevant configuration.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: The version of the tool that you are using. If a helm chart, please share the name of the chart.
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: search
|
||||
attributes:
|
||||
label: Search
|
||||
options:
|
||||
- label: I did search for other open and closed issues before opening this.
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Code of Conduct
|
||||
description: By submitting this issue, you agree to follow the CODE_OF_CONDUCT in this repository.
|
||||
options:
|
||||
- label: I agree to follow this project's Code of Conduct
|
||||
required: true
|
||||
- type: textarea
|
||||
id: ctx
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Anything else you would like to add
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: [triage, enhancement]
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
name: Other
|
||||
about: For misc. tasks like research or continued conversation
|
||||
title: ''
|
||||
labels: [triage]
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
@@ -0,0 +1,15 @@
|
||||
# The action uses an own Dockerfile on purpose because the root Dockerfile takes way too long to build for an action
|
||||
|
||||
FROM alpine:3.10
|
||||
|
||||
RUN apk add --no-cache \
|
||||
bash \
|
||||
ca-certificates \
|
||||
curl \
|
||||
wget \
|
||||
tar \
|
||||
jq
|
||||
|
||||
COPY get_polaris.sh /get_polaris.sh
|
||||
|
||||
ENTRYPOINT ["/get_polaris.sh"]
|
||||
@@ -0,0 +1,22 @@
|
||||
name: 'Install polaris'
|
||||
description: 'Download a specific polaris version'
|
||||
|
||||
inputs:
|
||||
version:
|
||||
description: 'version of polaris'
|
||||
required: true
|
||||
default: 'latest'
|
||||
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: './Dockerfile'
|
||||
args:
|
||||
- ${{ inputs.version }}
|
||||
|
||||
outputs:
|
||||
version:
|
||||
description: 'Version of polaris installed'
|
||||
|
||||
branding:
|
||||
icon: 'download-cloud'
|
||||
color: 'gray-dark'
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
if [[ -z "$INPUT_VERSION" ]]; then
|
||||
echo "Missing polaris version information"
|
||||
exit 1
|
||||
fi
|
||||
POLARIS_URL=https://github.com/FairwindsOps/polaris/releases/download/$INPUT_VERSION/polaris_linux_amd64.tar.gz
|
||||
polaris version | grep "$INPUT_VERSION" &> /dev/null
|
||||
if [ $? == 0 ]; then
|
||||
echo "Polaris $INPUT_VERSION is already installed! Exiting gracefully."
|
||||
exit 0
|
||||
else
|
||||
echo "Installing polaris to path from " $POLARIS_URL
|
||||
fi
|
||||
TARGET_FILE="polaris.tar.gz"
|
||||
curl -LJ -o $TARGET_FILE $POLARIS_URL
|
||||
mkdir polaris
|
||||
tar -xzf $TARGET_FILE -C polaris
|
||||
rm $TARGET_FILE
|
||||
echo "polaris" >> $GITHUB_PATH
|
||||
echo "::set-output name=version::$INPUT_VERSION"
|
||||
@@ -0,0 +1,20 @@
|
||||
## DO NOT EDIT - Managed by Terraform
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/docs"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 0
|
||||
ignore:
|
||||
- dependency-name: "*"
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
This PR fixes #
|
||||
|
||||
## Checklist
|
||||
* [ ] I have signed the CLA
|
||||
* [ ] I have updated/added any relevant documentation
|
||||
|
||||
## Description
|
||||
### What's the goal of this PR?
|
||||
|
||||
### What changes did you make?
|
||||
|
||||
### What alternative solution should we consider, if any?
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '32 1 * * *'
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v4
|
||||
with:
|
||||
exempt-issue-labels: pinned
|
||||
stale-pr-label: stale
|
||||
stale-issue-label: stale
|
||||
@@ -0,0 +1,27 @@
|
||||
name: Test setup-polaris
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build-int:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup polaris
|
||||
uses: ./.github/actions/setup-polaris
|
||||
with:
|
||||
version: 4.2.0
|
||||
- name: Use command
|
||||
run: polaris version
|
||||
|
||||
build-ext:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup polaris
|
||||
uses: fairwindsops/polaris/.github/actions/setup-polaris@master
|
||||
with:
|
||||
version: 4.2.0
|
||||
- name: Use command
|
||||
run: polaris version
|
||||
@@ -1,4 +1,8 @@
|
||||
# Binaries for programs and plugins
|
||||
# goreleaser is run via a wrapper that creates .goreleaser.yml from .goreleaser.yml.envsubst
|
||||
.goreleaser.yml
|
||||
# dist
|
||||
# # Binaries for programs and plugins
|
||||
.go-version
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
@@ -6,6 +10,7 @@
|
||||
*.dylib
|
||||
polaris
|
||||
|
||||
!cmd/polaris
|
||||
!deploy/helm/polaris
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
@@ -20,3 +25,9 @@ main
|
||||
|
||||
*-packr.go
|
||||
dist
|
||||
.vscode
|
||||
|
||||
*-test.yaml
|
||||
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
binary: polaris
|
||||
archive:
|
||||
replacements:
|
||||
darwin: Darwin
|
||||
linux: Linux
|
||||
windows: Windows
|
||||
386: i386
|
||||
amd64: x86_64
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
snapshot:
|
||||
name_template: "{{ .Tag }}-next"
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
brew:
|
||||
github:
|
||||
owner: reactiveops
|
||||
name: homebrew-tap
|
||||
folder: Formula
|
||||
description: Open Source Best Practices for Kubernetes
|
||||
test: |
|
||||
system "#{bin}/polaris --version"
|
||||
@@ -0,0 +1,113 @@
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
env:
|
||||
- GOBIN={{ .Env.TMPDIR }}/go-bin
|
||||
before:
|
||||
hooks:
|
||||
- go mod download
|
||||
- ./scripts/install-and-run-packr2.sh
|
||||
builds:
|
||||
- id: polaris
|
||||
ldflags:
|
||||
- -X main.Version={{.Version}} -X main.Commit={{.Commit}} -s -w
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
- GO111MODULE=on
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
- windows
|
||||
goarch:
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
goarm:
|
||||
- 6
|
||||
- 7
|
||||
archives:
|
||||
- id: polaris
|
||||
builds: ["polaris"]
|
||||
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}"
|
||||
signs:
|
||||
- cmd: cosign
|
||||
args: ["sign-blob", "--key=hashivault://cosign", "-output-signature=${signature}", "${artifact}"]
|
||||
artifacts: checksum
|
||||
release:
|
||||
# This is replaced using `envsubst`, depending on the git branch.
|
||||
disable: ${skip_release}
|
||||
prerelease: auto
|
||||
footer: |
|
||||
You can verify the signature of the checksums.txt file using [cosign](https://github.com/sigstore/cosign).
|
||||
|
||||
```
|
||||
cosign verify-blob checksums.txt --signature=checksums.txt.sig --key https://artifacts.fairwinds.com/cosign.pub
|
||||
```
|
||||
brews:
|
||||
- name: polaris
|
||||
# This is replaced using `envsubst`, depending on the git branch.
|
||||
skip_upload: ${skip_release}
|
||||
tap:
|
||||
owner: FairwindsOps
|
||||
name: homebrew-tap
|
||||
folder: Formula
|
||||
description: Open Source Best Practices for Kubernetes
|
||||
test: |
|
||||
system "#{bin}/polaris version"
|
||||
dockers:
|
||||
# There are multiple images to match the `--platform` docker build flag with
|
||||
# combinations of `GOOS`, `GOARCH`, and `GOARM`
|
||||
- image_templates:
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/amd64"
|
||||
- image_templates:
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
|
||||
use: buildx
|
||||
goarch: arm64
|
||||
goos: linux
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm64"
|
||||
docker_manifests:
|
||||
# Create DOcker manifests that make multiple architectures available within a tag,
|
||||
# and provide partial-version tags like 2, and 2.2.
|
||||
- name_template: quay.io/fairwinds/polaris:{{ .FullCommit }}
|
||||
image_templates:
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
|
||||
- name_template: quay.io/fairwinds/polaris:{{ .Env.feature_docker_tag }}
|
||||
# This is replaced using `envsubst`, depending on the git branch.
|
||||
skip_push: ${skip_feature_docker_tags}
|
||||
image_templates:
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
|
||||
- name_template: quay.io/fairwinds/polaris:latest
|
||||
# This is replaced using `envsubst`, depending on the git branch.
|
||||
skip_push: ${skip_release}
|
||||
image_templates:
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
|
||||
- name_template: quay.io/fairwinds/polaris:{{ .Tag }}
|
||||
# This is replaced using `envsubst`, depending on the git branch.
|
||||
skip_push: ${skip_release}
|
||||
image_templates:
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
|
||||
- name_template: quay.io/fairwinds/polaris:{{ .Major }}
|
||||
# This is replaced using `envsubst`, depending on the git branch.
|
||||
skip_push: ${skip_release}
|
||||
image_templates:
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
|
||||
- name_template: quay.io/fairwinds/polaris:{{ .Major }}.{{ .Minor }}
|
||||
# This is replaced using `envsubst`, depending on the git branch.
|
||||
skip_push: ${skip_release}
|
||||
image_templates:
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
|
||||
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
|
||||
@@ -0,0 +1,24 @@
|
||||
header:
|
||||
license:
|
||||
spdx-id: Apache-2.0
|
||||
copyright-owner: 'FairwindsOps, Inc.'
|
||||
content: |
|
||||
// Copyright 2019 FairwindsOps Inc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
paths:
|
||||
- '**/*.go'
|
||||
comment: on-failure
|
||||
dependency:
|
||||
files:
|
||||
- go.mod
|
||||
@@ -1,45 +0,0 @@
|
||||
# 0.1.0
|
||||
* Dashboard fully functional
|
||||
* Validating webhook functional, but still considered beta
|
||||
* Checks:
|
||||
* Health
|
||||
* readiness probe missing
|
||||
* liveness probe missing
|
||||
* Images
|
||||
* tag not specified
|
||||
* pull policy not always
|
||||
* Networking
|
||||
* host network set
|
||||
* host port set
|
||||
* Resources
|
||||
* cpu/memory requests missing
|
||||
* cpu/memory limits missing
|
||||
* cpu/memory ranges exceeded
|
||||
* Security
|
||||
* security capabilities
|
||||
* host IPC set
|
||||
* host PID set
|
||||
* not read-only fs
|
||||
* privilege escalation allowed
|
||||
* run as root allowed
|
||||
* run as privileged
|
||||
|
||||
# 0.1.1
|
||||
* [Fix](https://github.com/reactiveops/polaris/issues/93): missing `config.yaml` and dashboard assets in binary releases
|
||||
* Added some tests and better error handling
|
||||
|
||||
# 0.1.2
|
||||
* Stored all third-party assets (e.g. Charts.js) to local files to support offline dashboard viewing
|
||||
* Fix: custom configs in `ConfigMap` not respected
|
||||
|
||||
# 0.1.3
|
||||
* [Fix](https://github.com/reactiveops/polaris/issues/109): dashboard not updating when running persistently
|
||||
|
||||
# 0.1.4
|
||||
* [Fix](https://github.com/reactiveops/polaris/issues/116): details pages getting template errors
|
||||
* [Fix](https://github.com/reactiveops/polaris/issues/114): support all auth providers
|
||||
* [Fix](https://github.com/reactiveops/polaris/issues/112): Ignore readiness probe for initContainers
|
||||
|
||||
# 0.1.5
|
||||
* [Fix](https://github.com/reactiveops/polaris/issues/125): ignore limits/requests for initContainers
|
||||
* [Fix](https://github.com/reactiveops/polaris/issues/132): support custom base path
|
||||
@@ -1 +1,2 @@
|
||||
* @bobby-brennan @endzyme @kimschles @robscott
|
||||
## DO NOT EDIT - Managed by Terraform
|
||||
* @rbren @mggude
|
||||
|
||||
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
|
||||
reported by contacting the project team at opensource@fairwinds.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
@@ -71,4 +71,4 @@ This Code of Conduct is adapted from the [Contributor Covenant][homepage], versi
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
# Contributing
|
||||
|
||||
Issues, whether bugs, tasks, or feature requests are essential for keeping Polaris great. We believe it should be as easy as possible to contribute changes that get things working in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project adheres to a [code of conduct](CODE_OF_CONDUCT.md). Please review this document before contributing to this project.
|
||||
|
||||
## Project Structure
|
||||
|
||||
Polaris is built on top of [controller-runtime](https://github.com/kubernetes-sigs/controller-runtime). It can run in 3 different modes, a dashboard, a webhook, or a reporter that prints or exports validation results. All of these modes make use of the shared `validator` and `config` packages. Adding new validations is possible by only making additions to those packages.
|
||||
|
||||
## Getting Started
|
||||
|
||||
We label issues with the ["good first issue" tag](https://github.com/reactiveops/polaris/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) if we believe they'll be a good starting point for new contributors. If you're interested in working on an issue, please start a conversation on that issue, and we can help answer any questions as they come up.
|
||||
|
||||
## Running Tests
|
||||
|
||||
The following commands are all required to pass as part of Polaris testing:
|
||||
|
||||
```
|
||||
go list ./... | grep -v vendor | xargs golint -set_exit_status
|
||||
go list ./... | grep -v vendor | xargs go vet
|
||||
go test ./pkg/... -v -coverprofile cover.out
|
||||
```
|
||||
|
||||
## Creating a New Issue
|
||||
|
||||
If you've encountered an issue that is not already reported, please create an issue that contains the following:
|
||||
|
||||
- Clear description of the issue
|
||||
- Steps to reproduce it
|
||||
- Appropriate labels
|
||||
|
||||
## Creating a Pull Request
|
||||
|
||||
Each new pull request should:
|
||||
|
||||
- Reference any related issues
|
||||
- Add tests that show the issues have been solved
|
||||
- Pass existing tests and linting
|
||||
- Contain a clear indication of if they're ready for review or a work in progress
|
||||
- Be up to date and/or rebased on the master branch
|
||||
|
||||
## Creating a new release
|
||||
* Change the version number everywhere. E.g. for `0.1.4` to `0.1.5`:
|
||||
```
|
||||
find ./ -type f ! -path "./vendor/*" ! -path "./.git/*" ! -name CHANGELOG.md -exec sed -i 's/0\.1\.4/0.1.5/g' {} \;
|
||||
```
|
||||
* Add relevant entries to CHANGELOG.md
|
||||
* Create a PR to merge your changes
|
||||
* Once the PR is merged, wait for CircleCI to finish building the merge commit
|
||||
* Tag and push the latest:
|
||||
```
|
||||
git checkout master
|
||||
git pull
|
||||
git tag $VERSION
|
||||
git push --tags
|
||||
```
|
||||
* CircleCI will add an entry to the releases page on GitHub
|
||||
@@ -1,17 +1,21 @@
|
||||
FROM golang:1.12.4 AS build-env
|
||||
WORKDIR /go/src/github.com/reactiveops/polaris/
|
||||
FROM alpine:20230208
|
||||
|
||||
COPY . .
|
||||
RUN go get -u github.com/gobuffalo/packr/v2/packr2
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 packr2 build -a -o polaris *.go
|
||||
LABEL org.opencontainers.image.authors="FairwindsOps, Inc." \
|
||||
org.opencontainers.image.vendor="FairwindsOps, Inc." \
|
||||
org.opencontainers.image.title="polaris" \
|
||||
org.opencontainers.image.description="Polaris is a cli tool to help discover deprecated apiVersions in Kubernetes" \
|
||||
org.opencontainers.image.documentation="https://polaris.docs.fairwinds.com/" \
|
||||
org.opencontainers.image.source="https://github.com/FairwindsOps/polaris" \
|
||||
org.opencontainers.image.url="https://github.com/FairwindsOps/polaris" \
|
||||
org.opencontainers.image.licenses="Apache License 2.0"
|
||||
|
||||
FROM alpine:3.9
|
||||
WORKDIR /usr/local/bin
|
||||
RUN apk -U upgrade
|
||||
RUN apk --no-cache add ca-certificates
|
||||
|
||||
RUN addgroup -S polaris && adduser -u 1200 -S polaris -G polaris
|
||||
USER 1200
|
||||
COPY --from=build-env /go/src/github.com/reactiveops/polaris/polaris .
|
||||
COPY polaris .
|
||||
|
||||
WORKDIR /opt/app
|
||||
|
||||
|
||||
@@ -1,512 +0,0 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "cloud.google.com/go"
|
||||
packages = ["compute/metadata"]
|
||||
revision = "775730d6e48254a2430366162cf6298e5368833c"
|
||||
version = "v0.39.0"
|
||||
|
||||
[[projects]]
|
||||
name = "contrib.go.opencensus.io/exporter/ocagent"
|
||||
packages = ["."]
|
||||
revision = "dcb33c7f3b7cfe67e8a2cea10207ede1b7c40764"
|
||||
version = "v0.4.12"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Azure/go-autorest"
|
||||
packages = ["autorest","autorest/adal","autorest/azure","autorest/date","logger","tracing"]
|
||||
revision = "fe1ebaab71ae2a2ab8a55f62ebe54cffd842acc2"
|
||||
version = "v12.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/appscode/jsonpatch"
|
||||
packages = ["."]
|
||||
revision = "7c0e3b262f30165a8ec3d0b4c6059fd92703bfb2"
|
||||
version = "1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/beorn7/perks"
|
||||
packages = ["quantile"]
|
||||
revision = "4b2b341e8d7715fae06375aa633dbb6e91b3fb46"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/census-instrumentation/opencensus-proto"
|
||||
packages = ["gen-go/agent/common/v1","gen-go/agent/metrics/v1","gen-go/agent/trace/v1","gen-go/metrics/v1","gen-go/resource/v1","gen-go/trace/v1"]
|
||||
revision = "a105b96453fe85139acc07b68de48f2cbdd71249"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||
version = "v3.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/evanphx/json-patch"
|
||||
packages = ["."]
|
||||
revision = "5858425f75500d40c52783dce87d085a483ce135"
|
||||
version = "v4.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-logr/logr"
|
||||
packages = ["."]
|
||||
revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-logr/zapr"
|
||||
packages = ["."]
|
||||
revision = "03f06a783fbb7dfaf3f629c7825480e43a7105e6"
|
||||
version = "v0.1.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gobuffalo/envy"
|
||||
packages = ["."]
|
||||
revision = "043cb4b8af871b49563291e32c66bb84378a60ac"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gobuffalo/genny"
|
||||
packages = ["."]
|
||||
revision = "05dc5921e98daa5d406f90c2844ff163cb1e1c4e"
|
||||
version = "v0.1.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gobuffalo/gogen"
|
||||
packages = [".","goimports","gomods"]
|
||||
revision = "5482e6ef5d999f8cfa9b038a53953c9b4ee090af"
|
||||
version = "v0.1.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/gobuffalo/logger"
|
||||
packages = ["."]
|
||||
revision = "86e12af44bc273e0063fad5b6ad588890b8cfe6b"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gobuffalo/mapi"
|
||||
packages = ["."]
|
||||
revision = "0bb5e840be332d4280e40f2e6c50777c615bbac5"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gobuffalo/packd"
|
||||
packages = ["."]
|
||||
revision = "9efbb667f2024a9370cadda45a57a0657c88a6fb"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gobuffalo/packr"
|
||||
packages = ["v2","v2/file","v2/file/resolver","v2/file/resolver/encoding/hex","v2/jam/parser","v2/plog"]
|
||||
revision = "cda4ac25577350dac682c8715dc6659327232596"
|
||||
version = "v2.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/gobuffalo/syncx"
|
||||
packages = ["."]
|
||||
revision = "33c29581e754bd354236e977dfe426e55331c45d"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gogo/protobuf"
|
||||
packages = ["proto","sortkeys"]
|
||||
revision = "ba06b47c162d49f2af050fb4c75bcbc86a159d5c"
|
||||
version = "v1.2.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/golang/groupcache"
|
||||
packages = ["lru"]
|
||||
revision = "5b532d6fd5efaf7fa130d4e859a2fde0fc3a9e1b"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = ["jsonpb","proto","protoc-gen-go/descriptor","protoc-gen-go/generator","protoc-gen-go/generator/internal/remap","protoc-gen-go/plugin","ptypes","ptypes/any","ptypes/duration","ptypes/struct","ptypes/timestamp","ptypes/wrappers"]
|
||||
revision = "b5d812f8a3706043e23a9cd5babf2e5423744d30"
|
||||
version = "v1.3.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/google/btree"
|
||||
packages = ["."]
|
||||
revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/google/gofuzz"
|
||||
packages = ["."]
|
||||
revision = "f140a6486e521aad38f5917de355cbf147cc0496"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/google/uuid"
|
||||
packages = ["."]
|
||||
revision = "0cd6bf5da1e1c83f8b45653022c74f71af0538a4"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/googleapis/gnostic"
|
||||
packages = ["OpenAPIv2","compiler","extensions"]
|
||||
revision = "7c663266750e7d82587642f65e60bc4083f1f84e"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/gophercloud/gophercloud"
|
||||
packages = [".","openstack","openstack/identity/v2/tenants","openstack/identity/v2/tokens","openstack/identity/v3/tokens","openstack/utils","pagination"]
|
||||
revision = "b3a23cc94cc51857a508733a0bd3d6ef0bfc16d9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/mux"
|
||||
packages = ["."]
|
||||
revision = "ed099d42384823742bba0bf9a72b53b55c9e2e38"
|
||||
version = "v1.7.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/gregjones/httpcache"
|
||||
packages = [".","diskcache"]
|
||||
revision = "3befbb6ad0cc97d4c25d851e9528915809e1a22f"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/grpc-ecosystem/grpc-gateway"
|
||||
packages = ["internal","runtime","utilities"]
|
||||
revision = "8fd5fd9d19ce68183a6b0934519dfe7fe6269612"
|
||||
version = "v1.9.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/hashicorp/golang-lru"
|
||||
packages = [".","simplelru"]
|
||||
revision = "7087cb70de9f7a8bc0a10c375cb0d2280a8edf9c"
|
||||
version = "v0.5.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/imdario/mergo"
|
||||
packages = ["."]
|
||||
revision = "7c29201646fa3de8506f701213473dd407f19646"
|
||||
version = "v0.3.7"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/joho/godotenv"
|
||||
packages = ["."]
|
||||
revision = "23d116af351c84513e1946b527c88823e476be13"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/json-iterator/go"
|
||||
packages = ["."]
|
||||
revision = "0ff49de124c6f76f8494e194af75bde0f1a49a29"
|
||||
version = "v1.1.6"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/karrick/godirwalk"
|
||||
packages = ["."]
|
||||
revision = "5e617d9cfec6f870e63b168e9a2fb7c490a1c108"
|
||||
version = "v1.10.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/konsorten/go-windows-terminal-sequences"
|
||||
packages = ["."]
|
||||
revision = "f55edac94c9bbba5d6182a4be46d86a2c9b5b50e"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/markbates/oncer"
|
||||
packages = ["."]
|
||||
revision = "bf2de49a0be218916e69a11d22866e6cd0a560f2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/markbates/safe"
|
||||
packages = ["."]
|
||||
revision = "6fea05a5732486546a4836b7a1d596c5ec687b98"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||
packages = ["pbutil"]
|
||||
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/modern-go/concurrent"
|
||||
packages = ["."]
|
||||
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
|
||||
version = "1.0.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/modern-go/reflect2"
|
||||
packages = ["."]
|
||||
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
|
||||
version = "1.0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pborman/uuid"
|
||||
packages = ["."]
|
||||
revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1"
|
||||
version = "v1.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/petar/GoLLRB"
|
||||
packages = ["llrb"]
|
||||
revision = "33fb24c13b99c46c93183c291836c573ac382536"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/peterbourgon/diskv"
|
||||
packages = ["."]
|
||||
revision = "0be1b92a6df0e4f5cb0a5d15fb7f643d0ad93ce6"
|
||||
version = "v3.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
|
||||
version = "v0.8.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/prometheus/client_golang"
|
||||
packages = ["prometheus","prometheus/internal","prometheus/promhttp"]
|
||||
revision = "50c4339db732beb2165735d2cde0bff78eb3c5a5"
|
||||
version = "v0.9.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/prometheus/client_model"
|
||||
packages = ["go"]
|
||||
revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/prometheus/common"
|
||||
packages = ["expfmt","internal/bitbucket.org/ww/goautoneg","model"]
|
||||
revision = "1ba88736f028e37bc17328369e94a537ae9e0234"
|
||||
version = "v0.4.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/prometheus/procfs"
|
||||
packages = [".","internal/fs"]
|
||||
revision = "9935e8e0588d26307d1d4a07bed7bd47271b6bbd"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/rogpeppe/go-internal"
|
||||
packages = ["modfile","module","semver"]
|
||||
revision = "438578804ca6f31be148c27683afc419ce47c06e"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/sirupsen/logrus"
|
||||
packages = ["."]
|
||||
revision = "839c75faf7f98a33d445d181f3018b5c3409a45e"
|
||||
version = "v1.4.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
|
||||
version = "v1.0.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = ["assert"]
|
||||
revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "gitlab.com/golang-commonmark/html"
|
||||
packages = ["."]
|
||||
revision = "cfaf75183c4a5f0e44e3d51ece1065accafdd2b3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "gitlab.com/golang-commonmark/linkify"
|
||||
packages = ["."]
|
||||
revision = "c22b7bdb117955ff2cc0e3724083d35e3419d71e"
|
||||
|
||||
[[projects]]
|
||||
name = "gitlab.com/golang-commonmark/markdown"
|
||||
packages = ["."]
|
||||
revision = "772775880e1fbf39a7804149ed11c0f714ec89fe"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "gitlab.com/golang-commonmark/mdurl"
|
||||
packages = ["."]
|
||||
revision = "e5bce34c34f29ecf232fec34f3982e55533ec14e"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "gitlab.com/golang-commonmark/puny"
|
||||
packages = ["."]
|
||||
revision = "2cd490539afe7c6fc0eda6c59ef88fa93a00ea0d"
|
||||
|
||||
[[projects]]
|
||||
name = "go.opencensus.io"
|
||||
packages = [".","internal","internal/tagencoding","metric/metricdata","metric/metricproducer","plugin/ocgrpc","plugin/ochttp","plugin/ochttp/propagation/b3","plugin/ochttp/propagation/tracecontext","resource","stats","stats/internal","stats/view","tag","trace","trace/internal","trace/propagation","trace/tracestate"]
|
||||
revision = "43463a80402d8447b7fce0d2c58edf1687ff0b58"
|
||||
version = "v0.19.3"
|
||||
|
||||
[[projects]]
|
||||
name = "go.uber.org/atomic"
|
||||
packages = ["."]
|
||||
revision = "df976f2515e274675050de7b3f42545de80594fd"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[projects]]
|
||||
name = "go.uber.org/multierr"
|
||||
packages = ["."]
|
||||
revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "go.uber.org/zap"
|
||||
packages = [".","buffer","internal/bufferpool","internal/color","internal/exit","zapcore"]
|
||||
revision = "27376062155ad36be76b0f12cf1572a221d3a48c"
|
||||
version = "v1.10.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["ssh/terminal"]
|
||||
revision = "22d7a77e9e5f409e934ed268692e56707cd169e5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
packages = ["context","context/ctxhttp","http/httpguts","http2","http2/hpack","idna","internal/timeseries","trace"]
|
||||
revision = "3ec19112720433827bbce8be9342797f5a6aaaf9"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/oauth2"
|
||||
packages = [".","google","internal","jws","jwt"]
|
||||
revision = "950ef44c6e079baf075030377d90bf0c7e4b7b7a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sync"
|
||||
packages = ["semaphore"]
|
||||
revision = "112230192c580c3556b8cee6403af37a4fc5f28c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix","windows"]
|
||||
revision = "ad400b1274690a55531a013560dc08706088f82b"
|
||||
|
||||
[[projects]]
|
||||
name = "golang.org/x/text"
|
||||
packages = ["collate","collate/build","internal/colltab","internal/gen","internal/language","internal/language/compact","internal/tag","internal/triegen","internal/ucd","language","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"]
|
||||
revision = "342b2e1fbaa52c93f31447ad2c6abc048c63e475"
|
||||
version = "v0.3.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/time"
|
||||
packages = ["rate"]
|
||||
revision = "9d24e82272b4f38b78bc8cff74fa936d31ccd8ef"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/tools"
|
||||
packages = ["go/ast/astutil","go/gcexportdata","go/internal/gcimporter","go/internal/packagesdriver","go/packages","go/types/typeutil","imports","internal/fastwalk","internal/gopathwalk","internal/module","internal/semver"]
|
||||
revision = "d88f79806bbd013f54a668506864ce559edf6f0a"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/api"
|
||||
packages = ["support/bundler"]
|
||||
revision = "721295fe20d585ce7e948146f82188429d14da33"
|
||||
version = "v0.5.0"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/appengine"
|
||||
packages = [".","internal","internal/app_identity","internal/base","internal/datastore","internal/log","internal/modules","internal/remote_api","internal/urlfetch","urlfetch"]
|
||||
revision = "4c25cacc810c02874000e4f7071286a8e96b2515"
|
||||
version = "v1.6.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/api/httpbody","googleapis/rpc/status","protobuf/field_mask"]
|
||||
revision = "bb713bdc0e5239f2b68e560efbe1c701a6fe78f9"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/grpc"
|
||||
packages = [".","balancer","balancer/base","balancer/roundrobin","binarylog/grpc_binarylog_v1","codes","connectivity","credentials","credentials/internal","encoding","encoding/proto","grpclog","internal","internal/backoff","internal/balancerload","internal/binarylog","internal/channelz","internal/envconfig","internal/grpcrand","internal/grpcsync","internal/syscall","internal/transport","keepalive","metadata","naming","peer","resolver","resolver/dns","resolver/passthrough","stats","status","tap"]
|
||||
revision = "25c4f928eaa6d96443009bd842389fb4fa48664e"
|
||||
version = "v1.20.1"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/inf.v0"
|
||||
packages = ["."]
|
||||
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
|
||||
version = "v0.9.1"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
|
||||
version = "v2.2.2"
|
||||
|
||||
[[projects]]
|
||||
name = "k8s.io/api"
|
||||
packages = ["admission/v1beta1","admissionregistration/v1alpha1","admissionregistration/v1beta1","apps/v1","apps/v1beta1","apps/v1beta2","auditregistration/v1alpha1","authentication/v1","authentication/v1beta1","authorization/v1","authorization/v1beta1","autoscaling/v1","autoscaling/v2beta1","autoscaling/v2beta2","batch/v1","batch/v1beta1","batch/v2alpha1","certificates/v1beta1","coordination/v1beta1","core/v1","events/v1beta1","extensions/v1beta1","networking/v1","policy/v1beta1","rbac/v1","rbac/v1alpha1","rbac/v1beta1","scheduling/v1alpha1","scheduling/v1beta1","settings/v1alpha1","storage/v1","storage/v1alpha1","storage/v1beta1"]
|
||||
revision = "05914d821849570fba9eacfb29466f2d8d3cd229"
|
||||
version = "kubernetes-1.13.1"
|
||||
|
||||
[[projects]]
|
||||
name = "k8s.io/apimachinery"
|
||||
packages = ["pkg/api/errors","pkg/api/meta","pkg/api/resource","pkg/apis/meta/internalversion","pkg/apis/meta/v1","pkg/apis/meta/v1/unstructured","pkg/apis/meta/v1beta1","pkg/conversion","pkg/conversion/queryparams","pkg/fields","pkg/labels","pkg/runtime","pkg/runtime/schema","pkg/runtime/serializer","pkg/runtime/serializer/json","pkg/runtime/serializer/protobuf","pkg/runtime/serializer/recognizer","pkg/runtime/serializer/streaming","pkg/runtime/serializer/versioning","pkg/selection","pkg/types","pkg/util/cache","pkg/util/clock","pkg/util/diff","pkg/util/errors","pkg/util/framer","pkg/util/intstr","pkg/util/json","pkg/util/mergepatch","pkg/util/naming","pkg/util/net","pkg/util/runtime","pkg/util/sets","pkg/util/strategicpatch","pkg/util/uuid","pkg/util/validation","pkg/util/validation/field","pkg/util/wait","pkg/util/yaml","pkg/version","pkg/watch","third_party/forked/golang/json","third_party/forked/golang/reflect"]
|
||||
revision = "2b1284ed4c93a43499e781493253e2ac5959c4fd"
|
||||
version = "kubernetes-1.13.0"
|
||||
|
||||
[[projects]]
|
||||
name = "k8s.io/client-go"
|
||||
packages = ["discovery","discovery/fake","dynamic","kubernetes","kubernetes/fake","kubernetes/scheme","kubernetes/typed/admissionregistration/v1alpha1","kubernetes/typed/admissionregistration/v1alpha1/fake","kubernetes/typed/admissionregistration/v1beta1","kubernetes/typed/admissionregistration/v1beta1/fake","kubernetes/typed/apps/v1","kubernetes/typed/apps/v1/fake","kubernetes/typed/apps/v1beta1","kubernetes/typed/apps/v1beta1/fake","kubernetes/typed/apps/v1beta2","kubernetes/typed/apps/v1beta2/fake","kubernetes/typed/auditregistration/v1alpha1","kubernetes/typed/auditregistration/v1alpha1/fake","kubernetes/typed/authentication/v1","kubernetes/typed/authentication/v1/fake","kubernetes/typed/authentication/v1beta1","kubernetes/typed/authentication/v1beta1/fake","kubernetes/typed/authorization/v1","kubernetes/typed/authorization/v1/fake","kubernetes/typed/authorization/v1beta1","kubernetes/typed/authorization/v1beta1/fake","kubernetes/typed/autoscaling/v1","kubernetes/typed/autoscaling/v1/fake","kubernetes/typed/autoscaling/v2beta1","kubernetes/typed/autoscaling/v2beta1/fake","kubernetes/typed/autoscaling/v2beta2","kubernetes/typed/autoscaling/v2beta2/fake","kubernetes/typed/batch/v1","kubernetes/typed/batch/v1/fake","kubernetes/typed/batch/v1beta1","kubernetes/typed/batch/v1beta1/fake","kubernetes/typed/batch/v2alpha1","kubernetes/typed/batch/v2alpha1/fake","kubernetes/typed/certificates/v1beta1","kubernetes/typed/certificates/v1beta1/fake","kubernetes/typed/coordination/v1beta1","kubernetes/typed/coordination/v1beta1/fake","kubernetes/typed/core/v1","kubernetes/typed/core/v1/fake","kubernetes/typed/events/v1beta1","kubernetes/typed/events/v1beta1/fake","kubernetes/typed/extensions/v1beta1","kubernetes/typed/extensions/v1beta1/fake","kubernetes/typed/networking/v1","kubernetes/typed/networking/v1/fake","kubernetes/typed/policy/v1beta1","kubernetes/typed/policy/v1beta1/fake","kubernetes/typed/rbac/v1","kubernetes/typed/rbac/v1/fake","kubernetes/typed/rbac/v1alpha1","kubernetes/typed/rbac/v1alpha1/fake","kubernetes/typed/rbac/v1beta1","kubernetes/typed/rbac/v1beta1/fake","kubernetes/typed/scheduling/v1alpha1","kubernetes/typed/scheduling/v1alpha1/fake","kubernetes/typed/scheduling/v1beta1","kubernetes/typed/scheduling/v1beta1/fake","kubernetes/typed/settings/v1alpha1","kubernetes/typed/settings/v1alpha1/fake","kubernetes/typed/storage/v1","kubernetes/typed/storage/v1/fake","kubernetes/typed/storage/v1alpha1","kubernetes/typed/storage/v1alpha1/fake","kubernetes/typed/storage/v1beta1","kubernetes/typed/storage/v1beta1/fake","pkg/apis/clientauthentication","pkg/apis/clientauthentication/v1alpha1","pkg/apis/clientauthentication/v1beta1","pkg/version","plugin/pkg/client/auth","plugin/pkg/client/auth/azure","plugin/pkg/client/auth/exec","plugin/pkg/client/auth/gcp","plugin/pkg/client/auth/oidc","plugin/pkg/client/auth/openstack","rest","rest/watch","restmapper","testing","third_party/forked/golang/template","tools/auth","tools/cache","tools/clientcmd","tools/clientcmd/api","tools/clientcmd/api/latest","tools/clientcmd/api/v1","tools/leaderelection","tools/leaderelection/resourcelock","tools/metrics","tools/pager","tools/record","tools/reference","transport","util/buffer","util/cert","util/connrotation","util/flowcontrol","util/homedir","util/integer","util/jsonpath","util/retry","util/workqueue"]
|
||||
revision = "8d9ed539ba3134352c586810e749e58df4e94e4f"
|
||||
version = "kubernetes-1.13.1"
|
||||
|
||||
[[projects]]
|
||||
name = "k8s.io/klog"
|
||||
packages = ["."]
|
||||
revision = "e531227889390a39d9533dde61f590fe9f4b0035"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "k8s.io/kube-openapi"
|
||||
packages = ["pkg/util/proto"]
|
||||
revision = "a01b7d5d6c2258c80a4a10070f3dee9cd575d9c7"
|
||||
|
||||
[[projects]]
|
||||
name = "sigs.k8s.io/controller-runtime"
|
||||
packages = ["pkg/cache","pkg/cache/internal","pkg/client","pkg/client/apiutil","pkg/client/config","pkg/internal/recorder","pkg/leaderelection","pkg/manager","pkg/metrics","pkg/patch","pkg/recorder","pkg/runtime/inject","pkg/runtime/log","pkg/runtime/signals","pkg/webhook","pkg/webhook/admission","pkg/webhook/admission/builder","pkg/webhook/admission/types","pkg/webhook/internal/cert","pkg/webhook/internal/cert/generator","pkg/webhook/internal/cert/writer","pkg/webhook/internal/cert/writer/atomic","pkg/webhook/internal/metrics","pkg/webhook/types"]
|
||||
revision = "12d98582e72927b6cd0123e2b4e819f9341ce62c"
|
||||
version = "v0.1.10"
|
||||
|
||||
[[projects]]
|
||||
name = "sigs.k8s.io/yaml"
|
||||
packages = ["."]
|
||||
revision = "fd68e9863619f6ec2fdd8625fe1f02e7c877e480"
|
||||
version = "v1.1.0"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "205aba713edfc3b46886718dc86dbc24edc9e9758efd16724c2cdaa4256e6d50"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
@@ -1,62 +0,0 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "1.3.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "k8s.io/api"
|
||||
version = "kubernetes-1.13.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "k8s.io/apimachinery"
|
||||
version = "kubernetes-1.13.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "k8s.io/client-go"
|
||||
version = "kubernetes-1.13.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "sigs.k8s.io/controller-runtime"
|
||||
version = "0.1.10"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gobuffalo/packr"
|
||||
version = "2.2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gorilla/mux"
|
||||
version = "1.7.1"
|
||||
|
||||
[[constraint]]
|
||||
revision = "772775880e1fbf39a7804149ed11c0f714ec89fe"
|
||||
name = "gitlab.com/golang-commonmark/markdown"
|
||||
|
||||
[[constraint]]
|
||||
revision = "v1.3.1"
|
||||
name = "github.com/golang/protobuf"
|
||||
@@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2019 ReactiveOps
|
||||
Copyright 2019 FairwindsOps Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
helm-to-k8s:
|
||||
helm template deploy/helm/polaris/ --name polaris --namespace polaris --set templateOnly=true > deploy/dashboard.yaml
|
||||
helm template deploy/helm/polaris/ --name polaris --namespace polaris --set templateOnly=true --set webhook.enable=true --set dashboard.enable=false > deploy/webhook.yaml
|
||||
@@ -1,129 +1,63 @@
|
||||
<div align="center">
|
||||
<img src="/pkg/dashboard/assets/images/polaris-logo.png" alt="Polaris Logo" />
|
||||
<div align="center" class="no-border">
|
||||
<img src="https://polaris.docs.fairwinds.com/img/polaris-logo.png" alt="Polaris Logo">
|
||||
<br>
|
||||
|
||||
[![Version][version-image]][version-link] [![CircleCI][circleci-image]][circleci-link] [![Go Report Card][goreport-image]][goreport-link]
|
||||
<h3>Polaris is an open source policy engine for Kubernetes</h3>
|
||||
<a href="https://github.com/FairwindsOps/polaris/releases">
|
||||
<img src="https://img.shields.io/github/v/release/FairwindsOps/polaris">
|
||||
</a>
|
||||
<a href="https://goreportcard.com/report/github.com/FairwindsOps/polaris">
|
||||
<img src="https://goreportcard.com/badge/github.com/FairwindsOps/polaris">
|
||||
</a>
|
||||
<a href="https://circleci.com/gh/FairwindsOps/polaris">
|
||||
<img src="https://circleci.com/gh/FairwindsOps/polaris.svg?style=svg">
|
||||
</a>
|
||||
<a href="https://insights.fairwinds.com/gh/FairwindsOps/polaris">
|
||||
<img src="https://insights.fairwinds.com/v0/gh/FairwindsOps/polaris/badge.svg">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
[version-image]: https://img.shields.io/static/v1.svg?label=Version&message=0.1.5&color=239922
|
||||
[version-link]: https://github.com/reactiveops/polaris
|
||||
|
||||
[goreport-image]: https://goreportcard.com/badge/github.com/reactiveops/polaris
|
||||
[goreport-link]: https://goreportcard.com/report/github.com/reactiveops/polaris
|
||||
|
||||
[circleci-image]: https://circleci.com/gh/reactiveops/polaris.svg?style=svg
|
||||
[circleci-link]: https://circleci.com/gh/reactiveops/polaris.svg
|
||||
|
||||
Polaris helps keep your cluster healthy. It runs a variety of checks to ensure that Kubernetes deployments are configured using best practices that will avoid potential problems in the future. The project includes two primary components:
|
||||
|
||||
- A dashboard that provides an overview of how well current deployments are configured within a cluster.
|
||||
- An experimental validating webhook that can prevent any future deployments that do not live up to a configured standard.
|
||||
|
||||
**Want to learn more?** ReactiveOps holds [office hours on Zoom](https://zoom.us/j/951540265) the first Friday of every month, at 12pm Eastern. You can also reach out via email at `opensource@reactiveops.com`
|
||||
|
||||
## Dashboard
|
||||
|
||||
The Polaris dashboard is a way to get a simple visual overview of the current state of your Kubernetes deployments as well as a roadmap for what can be improved. The dashboard provides a cluster wide overview as well as breaking out results by category, namespace, and deployment.
|
||||
Polaris is an open source policy engine for Kubernetes that validates and remediates resource configuration. It includes 30+ built in configuration policies, as well as the ability to build custom policies with JSON Schema. When run on the command line or as a mutating webhook, Polaris can automatically remediate issues based on policy criteria.
|
||||
|
||||
Polaris can be run in three different modes:
|
||||
* As a [dashboard](https://polaris.docs.fairwinds.com/dashboard) - Validate Kubernetes resources against policy-as-code.
|
||||
* As an [admission controller](https://polaris.docs.fairwinds.com/admission-controller) - Automatically reject or modify workloads that don't adhere to your organization's policies.
|
||||
* As a [command-line tool](https://polaris.docs.fairwinds.com/infrastructure-as-code) - Incorporate policy-as-code into the CI/CD process to test local YAML files.
|
||||
<p align="center">
|
||||
<img src="/dashboard-screenshot.png" alt="Polaris Dashboard" />
|
||||
<img src="https://polaris.docs.fairwinds.com/img/architecture.svg" alt="Polaris Architecture" width="550"/>
|
||||
</p>
|
||||
|
||||
Our default standards in Polaris are rather high, so don’t be surprised if your score is lower than you might expect. A key goal for Polaris was to set a high standard and aim for great configuration by default. If the defaults we’ve included are too strict, it’s easy to adjust the configuration as part of the deployment configuration to better suit your workloads.
|
||||
## Documentation
|
||||
Check out the [documentation at docs.fairwinds.com](https://polaris.docs.fairwinds.com)
|
||||
|
||||
### Deploying
|
||||
<!-- Begin boilerplate -->
|
||||
## Join the Fairwinds Open Source Community
|
||||
|
||||
To deploy Polaris with kubectl:
|
||||
The goal of the Fairwinds Community is to exchange ideas, influence the open source roadmap,
|
||||
and network with fellow Kubernetes users.
|
||||
[Chat with us on Slack](https://join.slack.com/t/fairwindscommunity/shared_invite/zt-e3c6vj4l-3lIH6dvKqzWII5fSSFDi1g)
|
||||
or
|
||||
[join the user group](https://www.fairwinds.com/open-source-software-user-group) to get involved!
|
||||
|
||||
```
|
||||
kubectl apply -f https://raw.githubusercontent.com/reactiveops/polaris/master/deploy/dashboard.yaml
|
||||
```
|
||||
<a href="https://www.fairwinds.com/t-shirt-offer?utm_source=polaris&utm_medium=polaris&utm_campaign=polaris-tshirt">
|
||||
<img src="https://www.fairwinds.com/hubfs/Doc_Banners/Fairwinds_OSS_User_Group_740x125_v6.png" alt="Love Fairwinds Open Source? Share your business email and job title and we'll send you a free Fairwinds t-shirt!" />
|
||||
</a>
|
||||
|
||||
Polaris can also be deployed with Helm:
|
||||
## Other Projects from Fairwinds
|
||||
|
||||
```
|
||||
helm upgrade --install polaris deploy/helm/polaris/ --namespace polaris
|
||||
```
|
||||
Enjoying Polaris? Check out some of our other projects:
|
||||
* [Goldilocks](https://github.com/FairwindsOps/Goldilocks) - Right-size your Kubernetes Deployments by compare your memory and CPU settings against actual usage
|
||||
* [Pluto](https://github.com/FairwindsOps/Pluto) - Detect Kubernetes resources that have been deprecated or removed in future versions
|
||||
* [Nova](https://github.com/FairwindsOps/Nova) - Check to see if any of your Helm charts have updates available
|
||||
* [rbac-manager](https://github.com/FairwindsOps/rbac-manager) - Simplify the management of RBAC in your Kubernetes clusters
|
||||
|
||||
### Viewing the Dashboard
|
||||
Or [check out the full list](https://www.fairwinds.com/open-source-software?utm_source=polaris&utm_medium=polaris&utm_campaign=polaris)
|
||||
## Fairwinds Insights
|
||||
If you're interested in running Polaris in multiple clusters,
|
||||
tracking the results over time, integrating with Slack, Datadog, and Jira,
|
||||
or unlocking other functionality, check out
|
||||
[Fairwinds Insights](https://fairwinds.com/pricing),
|
||||
a platform for auditing and enforcing policy in Kubernetes clusters.
|
||||
|
||||
Once the dashboard is deployed, it can be viewed by using kubectl port-forward:
|
||||
|
||||
```
|
||||
kubectl port-forward --namespace polaris svc/polaris-dashboard 8080:80
|
||||
```
|
||||
|
||||
With the port forwarding in place, you can open http://localhost:8080 in your browser to view the dashboard.
|
||||
|
||||
### Using a Binary Release
|
||||
|
||||
If you'd prefer to run Polaris locally, binary releases are available on the [releases page](https://github.com/reactiveops/polaris/releases) or can be installed with [Homebrew](https://brew.sh/):
|
||||
|
||||
```
|
||||
brew tap reactiveops/tap
|
||||
brew install reactiveops/tap/polaris
|
||||
```
|
||||
|
||||
When running as a binary, Polaris will use your local kubeconfig to connect to a cluster. There are a variety of options available, but the most common usage will likely be to view the dashboard:
|
||||
|
||||
```
|
||||
polaris --dashboard
|
||||
```
|
||||
|
||||
## Webhook
|
||||
|
||||
Polaris includes experimental support for an optional validating webhook. This accepts the same configuration as the dashboard, and can run the same validations. This webhook will reject any deployments that trigger a validation error. This is indicative of the greater goal of Polaris, not just to encourage better configuration through dashboard visibility, but to actually enforce it with this webhook. *Although we are working towards greater stability and better test coverage, we do not currently consider this webhook component production ready.*
|
||||
|
||||
Unfortunately we have not found a way to display warnings as part of `kubectl` output unless we are rejecting a deployment altogether. That means that any checks with a severity of `warning` will still pass webhook validation, and the only evidence of that warning will either be in the Polaris dashboard or the Polaris webhook logs.
|
||||
|
||||
### Deploying
|
||||
|
||||
The Polaris webhook can be deployed with kubectl:
|
||||
|
||||
```
|
||||
kubectl apply -f https://raw.githubusercontent.com/reactiveops/polaris/master/deploy/webhook.yaml
|
||||
```
|
||||
|
||||
Alternatively, the webhook can be enabled with Helm by setting `webhook.enable` to true:
|
||||
|
||||
```
|
||||
helm upgrade --install polaris deploy/helm/polaris/ --namespace polaris --set webhook.enable=true
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Polaris supports a wide range of validations covering a number of Kubernetes best practices. Here's a sample configuration file that includes all currently supported checks. The [default configuration](https://github.com/reactiveops/polaris/blob/master/examples/config.yaml) contains a number of those checks. This repository also includes a sample [full configuration file](https://github.com/reactiveops/polaris/blob/master/examples/config-full.yaml) that enables all available checks.
|
||||
|
||||
Each check can be assigned a `severity`. Only checks with a severity of `error` or `warning` will be validated. The results of these validations are visible on the dashboard. In the case of the validating webhook, only failures with a severity of `error` will result in a change being rejected.
|
||||
|
||||
Polaris validation checks fall into several different categories:
|
||||
|
||||
- [Health Checks](docs/health-checks.md)
|
||||
- [Images](docs/images.md)
|
||||
- [Networking](docs/networking.md)
|
||||
- [Resources](docs/resources.md)
|
||||
- [Security](docs/security.md)
|
||||
|
||||
## CLI Options
|
||||
|
||||
* `config`: Specify a location for the Polaris config
|
||||
* `dashboard`: Runs the webserver for Polaris dashboard.
|
||||
* `dashboard-port`: Port for the dashboard webserver (default `8080`)
|
||||
* `dashboard-base-path`: Path on which the dashboard is being served (default `/`)
|
||||
* `webhook`: Runs the webhook webserver.
|
||||
* `webhook-port`: Port for the webhook webserver (default `9876`)
|
||||
* `disable-webhook-config-installer`: disable the installer in the webhook server, so it won't install webhook configuration resources during bootstrapping
|
||||
* `kubeconfig`: Paths to a kubeconfig. Only required if out-of-cluster.
|
||||
|
||||
## Contributing
|
||||
PRs welcome! Check out the [Contributing Guidelines](CONTRIBUTING.md),
|
||||
[Code of Conduct](CODE_OF_CONDUCT.md), and [Roadmap](ROADMAP.md) for more information.
|
||||
|
||||
## Further Information
|
||||
A history of changes to this project can be viewed in the [Changelog](CHANGELOG.md)
|
||||
|
||||
If you'd like to learn more about Polaris, or if you'd like to speak with
|
||||
a Kubernetes expert, you can contact `info@reactiveops.com` or [visit our website](https://reactiveops.com)
|
||||
|
||||
## License
|
||||
Apache License 2.0
|
||||
<a href="https://fairwinds.com/pricing">
|
||||
<img src="https://www.fairwinds.com/hubfs/Doc_Banners/Fairwinds_Polaris_Ad.png" alt="Fairwinds Insights" />
|
||||
</a>
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
# Polaris Roadmap
|
||||
We plan to continue expanding the list of checks available to Polaris users,
|
||||
as well as the project's overall functionality.
|
||||
|
||||
If you have ideas for a new check, or for new Polaris features,
|
||||
you can submit a pull request for this file, or open an issue in GitHub.
|
||||
|
||||
## Features
|
||||
### Validating Webhook
|
||||
The validating webhook rejects incoming workloads if they cause `error`-level
|
||||
issues, as defined by the Polaris configuration.
|
||||
|
||||
The webhook server is currently functional, but largely untested. Because
|
||||
the validating webhook has the potential to cause headaches for users,
|
||||
we have marked it as `beta` for now.
|
||||
|
||||
We will continue to gather feedback here and will move the webhook out of `beta`
|
||||
when we feel it's ready.
|
||||
|
||||
#### TODO
|
||||
* Pass `warning`-level messages back to `kubectl` if possible (may require changes
|
||||
to core k8s or `kubectl`)
|
||||
|
||||
## Ability to override checks
|
||||
We plan to add the ability to override Polaris checks for particular namespaces
|
||||
and workloads. This may be something that is set in the Polaris configuration,
|
||||
or an annotation that can be added to the resource definition.
|
||||
|
||||
This is important, as certain workloads have good reason to skip particular Polaris
|
||||
checks - for instance, the `dns-controller` deployment in `kube-system` needs to have
|
||||
the host network configured.
|
||||
|
||||
## Checks
|
||||
These are checks that we plan to implement. If you have requests or ideas,
|
||||
let us know! You can submit a pull request for this file, or open an issue in GitHub.
|
||||
|
||||
### Images
|
||||
* List of allowed/disallowed registries
|
||||
|
||||
### New controller types
|
||||
Currently we only look at Deployments. We plan to also validate these types of controllers:
|
||||
* StatefulSet
|
||||
* DaemonSet
|
||||
* Job
|
||||
* CronJob
|
||||
* ReplicaSet
|
||||
|
||||
### Check non-controllers
|
||||
We would like to implement checks for non-controller types, such as:
|
||||
* Ingress
|
||||
* Service
|
||||
* Secret
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
successMessage: The ServiceAccount will not be automounted
|
||||
failureMessage: The ServiceAccount will be automounted
|
||||
category: Security
|
||||
target: PodSpec
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required: ["serviceAccountName"]
|
||||
properties:
|
||||
serviceAccountName:
|
||||
type: string
|
||||
automountServiceAccountToken:
|
||||
type: boolean
|
||||
not:
|
||||
const: true
|
||||
additionalSchemaStrings:
|
||||
ServiceAccount: |
|
||||
type: object
|
||||
required:
|
||||
- metadata
|
||||
{{ if not (eq .Polaris.PodSpec.automountServiceAccountToken false) }}
|
||||
- automountServiceAccountToken
|
||||
{{ end }}
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
const: "{{ .Polaris.PodSpec.serviceAccountName }}"
|
||||
{{ if not (eq .Polaris.PodSpec.automountServiceAccountToken false) }}
|
||||
automountServiceAccountToken:
|
||||
type: boolean
|
||||
const: false
|
||||
{{ end }}
|
||||
@@ -0,0 +1,54 @@
|
||||
successMessage: The ClusterRole does not allow pods/exec or pods/attach
|
||||
failureMessage: The ClusterRole allows Pods/exec or pods/attach
|
||||
category: Security
|
||||
target: rbac.authorization.k8s.io/ClusterRole
|
||||
schemaString: |
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required: ["metadata", "rules"]
|
||||
anyOf:
|
||||
# Do not alert on default ClusterRoles.
|
||||
- properties:
|
||||
metadata:
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: 'admin'
|
||||
- const: "cluster-admin"
|
||||
- const: "edit"
|
||||
- pattern: '^system:'
|
||||
- const: "gce:podsecuritypolicy:calico-sa"
|
||||
- properties:
|
||||
rules:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
not:
|
||||
required: ["apiGroups", "resources", "verbs"]
|
||||
properties:
|
||||
apiGroups:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: ""
|
||||
- const: '*'
|
||||
resources:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: '*'
|
||||
- const: "pods/exec"
|
||||
- const: "pods/attach"
|
||||
verbs:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: '*'
|
||||
# An exec is also possible by `get`ing a web socket.
|
||||
- const: 'get'
|
||||
- const: 'create'
|
||||
@@ -0,0 +1,88 @@
|
||||
successMessage: The ClusterRoleBinding does not reference the default cluster-admin ClusterRole or one with wildcard permissions
|
||||
failureMessage: The ClusterRoleBinding references the default cluster-admin ClusterRole or one with wildcard permissions
|
||||
category: Security
|
||||
target: rbac.authorization.k8s.io/ClusterRoleBinding
|
||||
schemaString: |
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
anyOf:
|
||||
# Do not alert on default ClusterRoleBindings.
|
||||
- required: ["metadata"]
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: "cluster-admin"
|
||||
- pattern: '^system:'
|
||||
- const: "gce:podsecuritypolicy:calico-sa"
|
||||
- required: ["roleRef"]
|
||||
properties:
|
||||
roleRef:
|
||||
required: ["apiGroup", "kind", "name"]
|
||||
properties:
|
||||
apiGroup:
|
||||
type: string
|
||||
const: "rbac.authorization.k8s.io"
|
||||
kind:
|
||||
type: string
|
||||
const: "ClusterRole"
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
not:
|
||||
const: "cluster-admin"
|
||||
additionalSchemaStrings:
|
||||
rbac.authorization.k8s.io/ClusterRole: |
|
||||
type: object
|
||||
# Do not alert on default ClusterRoleBindings.
|
||||
{{ if and (ne .metadata.name "cluster-admin") (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
|
||||
required: ["metadata", "rules"]
|
||||
allOf:
|
||||
- properties:
|
||||
metadata:
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
const: "{{ .roleRef.name }}"
|
||||
- properties:
|
||||
rules:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
not:
|
||||
required: ["apiGroups", "resources", "verbs"]
|
||||
properties:
|
||||
apiGroups:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
const: "*"
|
||||
resources:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
const: '*'
|
||||
verbs:
|
||||
type: array
|
||||
uniqueItems: true
|
||||
oneOf:
|
||||
- contains:
|
||||
type: string
|
||||
const: '*'
|
||||
- minItems: 7
|
||||
items:
|
||||
type: string
|
||||
enum:
|
||||
- "get"
|
||||
- "list"
|
||||
- "watch"
|
||||
- "create"
|
||||
- "update"
|
||||
- "patch"
|
||||
- "delete"
|
||||
{{ end }}
|
||||
@@ -0,0 +1,82 @@
|
||||
successMessage: The ClusterRoleBinding does not reference a ClusterRole allowing pods/exec or pods/attach
|
||||
failureMessage: The ClusterRoleBinding references a ClusterRole that allows Pods/exec, allows pods/attach, or that does not exist
|
||||
category: Security
|
||||
target: rbac.authorization.k8s.io/ClusterRoleBinding
|
||||
schemaString: |
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
anyOf:
|
||||
# Do not alert on default ClusterRoleBindings.
|
||||
- required: ["metadata"]
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: "cluster-admin"
|
||||
- pattern: '^system:'
|
||||
- const: "gce:podsecuritypolicy:calico-sa"
|
||||
- required: ["roleRef"]
|
||||
properties:
|
||||
roleRef:
|
||||
required: ["apiGroup", "kind", "name"]
|
||||
properties:
|
||||
apiGroup:
|
||||
type: string
|
||||
const: "rbac.authorization.k8s.io"
|
||||
kind:
|
||||
type: string
|
||||
const: "ClusterRole"
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
additionalSchemaStrings:
|
||||
rbac.authorization.k8s.io/ClusterRole: |
|
||||
type: object
|
||||
# Do not alert on default ClusterRoleBindings.
|
||||
{{ if and (ne .metadata.name "cluster-admin") (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
|
||||
required: ["metadata", "rules"]
|
||||
allOf:
|
||||
- properties:
|
||||
metadata:
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
const: "{{ .roleRef.name }}"
|
||||
- properties:
|
||||
rules:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
not:
|
||||
required: ["apiGroups", "resources", "verbs"]
|
||||
properties:
|
||||
apiGroups:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: ""
|
||||
- const: '*'
|
||||
resources:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: '*'
|
||||
- const: "pods/exec"
|
||||
- const: "pods/attach"
|
||||
verbs:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: '*'
|
||||
# An exec is also possible by `get`ing a web socket.
|
||||
- const: 'get'
|
||||
- const: 'create'
|
||||
{{ end }}
|
||||
@@ -0,0 +1,32 @@
|
||||
successMessage: CPU limits are set
|
||||
failureMessage: CPU limits should be set
|
||||
category: Efficiency
|
||||
target: Container
|
||||
containers:
|
||||
exclude:
|
||||
- initContainer
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- resources
|
||||
properties:
|
||||
resources:
|
||||
type: object
|
||||
required:
|
||||
- limits
|
||||
properties:
|
||||
limits:
|
||||
type: object
|
||||
required:
|
||||
- cpu
|
||||
properties:
|
||||
cpu:
|
||||
type: string
|
||||
not:
|
||||
const: ''
|
||||
mutations:
|
||||
- op: add
|
||||
path: /resources/limits/cpu
|
||||
value: 100m
|
||||
comment: "TODO: Set this to the maximum amount of CPU you want your workload to use"
|
||||
@@ -0,0 +1,32 @@
|
||||
successMessage: CPU requests are set
|
||||
failureMessage: CPU requests should be set
|
||||
category: Efficiency
|
||||
target: Container
|
||||
containers:
|
||||
exclude:
|
||||
- initContainer
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- resources
|
||||
properties:
|
||||
resources:
|
||||
type: object
|
||||
required:
|
||||
- requests
|
||||
properties:
|
||||
requests:
|
||||
type: object
|
||||
required:
|
||||
- cpu
|
||||
properties:
|
||||
cpu:
|
||||
type: string
|
||||
not:
|
||||
const: ''
|
||||
mutations:
|
||||
- op: add
|
||||
path: /resources/requests/cpu
|
||||
value: 100m
|
||||
comment: "TODO: Set this to the amount of CPU you want to reserve for your workload"
|
||||
@@ -0,0 +1,31 @@
|
||||
successMessage: Container does not have any dangerous capabilities
|
||||
failureMessage: Container should not have dangerous capabilities
|
||||
category: Security
|
||||
target: Container
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
properties:
|
||||
securityContext:
|
||||
type: object
|
||||
properties:
|
||||
capabilities:
|
||||
type: object
|
||||
properties:
|
||||
add:
|
||||
type: array
|
||||
allOf:
|
||||
- not:
|
||||
contains:
|
||||
pattern: '^(?i)ALL$'
|
||||
- not:
|
||||
contains:
|
||||
pattern: '^(?i)SYS_ADMIN$'
|
||||
- not:
|
||||
contains:
|
||||
pattern: '^(?i)NET_ADMIN$'
|
||||
|
||||
|
||||
mutations:
|
||||
- op: remove
|
||||
path: /securityContext/capabilities/add
|
||||
@@ -0,0 +1,25 @@
|
||||
successMessage: Multiple replicas are scheduled
|
||||
failureMessage: Only one replica is scheduled
|
||||
category: Reliability
|
||||
target: Controller
|
||||
controllers:
|
||||
include:
|
||||
- Deployment
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
required:
|
||||
- replicas
|
||||
properties:
|
||||
replicas:
|
||||
type: integer
|
||||
minimum: 2
|
||||
mutations:
|
||||
- op: add
|
||||
path: /spec/replicas
|
||||
value: 3
|
||||
@@ -0,0 +1,14 @@
|
||||
successMessage: Host IPC is not configured
|
||||
failureMessage: Host IPC should not be configured
|
||||
category: Security
|
||||
target: PodSpec
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
properties:
|
||||
hostIPC:
|
||||
not:
|
||||
const: true
|
||||
mutations:
|
||||
- op: remove
|
||||
path: /hostIPC
|
||||
@@ -0,0 +1,14 @@
|
||||
successMessage: Host network is not configured
|
||||
failureMessage: Host network should not be configured
|
||||
category: Security
|
||||
target: PodSpec
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
properties:
|
||||
hostNetwork:
|
||||
not:
|
||||
const: true
|
||||
mutations:
|
||||
- op: remove
|
||||
path: /hostNetwork
|
||||
@@ -0,0 +1,14 @@
|
||||
successMessage: Host PID is not configured
|
||||
failureMessage: Host PID should not be configured
|
||||
category: Security
|
||||
target: PodSpec
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
properties:
|
||||
hostPID:
|
||||
not:
|
||||
const: true
|
||||
mutations:
|
||||
- op: remove
|
||||
path: /hostPID
|
||||
@@ -0,0 +1,18 @@
|
||||
successMessage: Host port is not configured
|
||||
failureMessage: Host port should not be configured
|
||||
category: Security
|
||||
target: Container
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
properties:
|
||||
ports:
|
||||
type: array
|
||||
items:
|
||||
properties:
|
||||
hostPort:
|
||||
const: 0
|
||||
mutations:
|
||||
- op: remove
|
||||
path: /ports/*/hostPort
|
||||
@@ -0,0 +1,60 @@
|
||||
successMessage: Container does not have any insecure capabilities
|
||||
failureMessage: Container should not have insecure capabilities
|
||||
category: Security
|
||||
target: Container
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- securityContext
|
||||
properties:
|
||||
securityContext:
|
||||
type: object
|
||||
required:
|
||||
- capabilities
|
||||
properties:
|
||||
capabilities:
|
||||
type: object
|
||||
required:
|
||||
- drop
|
||||
properties:
|
||||
drop:
|
||||
type: array
|
||||
oneOf:
|
||||
- contains:
|
||||
pattern: '^(?i)ALL$'
|
||||
- allOf:
|
||||
- contains:
|
||||
pattern: '^(?i)NET_ADMIN$'
|
||||
- contains:
|
||||
pattern: '^(?i)CHOWN$'
|
||||
- contains:
|
||||
pattern: '^(?i)DAC_OVERRIDE$'
|
||||
- contains:
|
||||
pattern: '^(?i)FSETID$'
|
||||
- contains:
|
||||
pattern: '^(?i)FOWNER$'
|
||||
- contains:
|
||||
pattern: '^(?i)MKNOD$'
|
||||
- contains:
|
||||
pattern: '^(?i)NET_RAW$'
|
||||
- contains:
|
||||
pattern: '^(?i)SETGID$'
|
||||
- contains:
|
||||
pattern: '^(?i)SETUID$'
|
||||
- contains:
|
||||
pattern: '^(?i)SETFCAP$'
|
||||
- contains:
|
||||
pattern: '^(?i)SETPCAP$'
|
||||
- contains:
|
||||
pattern: '^(?i)NET_BIND_SERVICE$'
|
||||
- contains:
|
||||
pattern: '^(?i)SYS_CHROOT$'
|
||||
- contains:
|
||||
pattern: '^(?i)KILL$'
|
||||
- contains:
|
||||
pattern: '^(?i)AUDIT_WRITE$'
|
||||
mutations:
|
||||
- op: replace
|
||||
path: /securityContext/capabilities
|
||||
value: {"drop": ["ALL"]}
|
||||
@@ -0,0 +1,89 @@
|
||||
successMessage: One of AppArmor, Seccomp, SELinux, or dropping Linux Capabilities are used to restrict containers using unwanted privileges
|
||||
FailureMessage: Use one of AppArmor, Seccomp, SELinux, or dropping Linux Capabilities to restrict containers using unwanted privileges
|
||||
category: Security
|
||||
target: Container
|
||||
schemaString: |
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
definitions:
|
||||
podOrContainerSeccompProfile:
|
||||
type: object
|
||||
{{ $podSeccompProfileType := .Polaris.PodSpec.securityContext.seccompProfile.type }}
|
||||
required:
|
||||
{{ if or (not $podSeccompProfileType) (eq $podSeccompProfileType "Unconfined") }}
|
||||
- securityContext
|
||||
{{ end }}
|
||||
properties:
|
||||
securityContext:
|
||||
type: object
|
||||
required:
|
||||
{{ if or (not $podSeccompProfileType) (eq $podSeccompProfileType "Unconfined") }}
|
||||
- seccompProfile
|
||||
{{ end }}
|
||||
properties:
|
||||
seccompProfile:
|
||||
type: object
|
||||
required:
|
||||
{{ if or (not $podSeccompProfileType) (eq $podSeccompProfileType "Unconfined") }}
|
||||
- type
|
||||
{{ end }}
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
allOf:
|
||||
- not:
|
||||
const: "Unconfined"
|
||||
{{ if or (not $podSeccompProfileType) (eq $podSeccompProfileType "Unconfined") }}
|
||||
- minLength: 1
|
||||
{{ end }}
|
||||
podOrContainerSELinuxOptions:
|
||||
type: object
|
||||
{{ $podSELinuxOptions := .Polaris.PodSpec.securityContext.seLinuxOptions }}
|
||||
{{ if not $podSELinuxOptions }}
|
||||
required: ["securityContext"]
|
||||
properties:
|
||||
securityContext:
|
||||
type: object
|
||||
required: ["seLinuxOptions"]
|
||||
properties:
|
||||
seLinuxOptions:
|
||||
type: object
|
||||
minProperties: 1
|
||||
{{ end }}
|
||||
containerDropCapabilities:
|
||||
type: object
|
||||
required: ["securityContext"]
|
||||
properties:
|
||||
securityContext:
|
||||
type: object
|
||||
required: ["capabilities"]
|
||||
properties:
|
||||
capabilities:
|
||||
type: object
|
||||
required: ["drop"]
|
||||
properties:
|
||||
drop:
|
||||
type: array
|
||||
minItems: 1
|
||||
add:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
not:
|
||||
pattern: '^(?i)ALL$'
|
||||
# End of definitions
|
||||
{{/* Check for AppArmor which uses pod annotations. IF pod fields are missing,
|
||||
require one of the other hardening measures. */}}
|
||||
{{ $annotationName := (print "container.apparmor.security.beta.kubernetes.io/" .Polaris.Container.name) }}
|
||||
{{/* Checking annotations before using index() avoids a nil panic when there are no annotations */}}
|
||||
{{ $annotationExists := false }}
|
||||
{{ if .Polaris.PodTemplate.metadata.annotations }}
|
||||
{{ $annotationExists = index .Polaris "PodTemplate" "metadata" "annotations" $annotationName }}
|
||||
{{ end }}
|
||||
{{ if $annotationExists }}
|
||||
type: object
|
||||
{{ else }}
|
||||
anyOf:
|
||||
- $ref: "#/definitions/podOrContainerSeccompProfile"
|
||||
- $ref: "#/definitions/podOrContainerSELinuxOptions"
|
||||
- $ref: "#/definitions/containerDropCapabilities"
|
||||
{{ end}}
|
||||
@@ -0,0 +1,26 @@
|
||||
successMessage: Liveness probe is configured
|
||||
failureMessage: Liveness probe should be configured
|
||||
category: Reliability
|
||||
controllers:
|
||||
exclude:
|
||||
- Job
|
||||
- CronJob
|
||||
containers:
|
||||
exclude:
|
||||
- initContainer
|
||||
target: Container
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- livenessProbe
|
||||
properties:
|
||||
livenessProbe:
|
||||
type: object
|
||||
not:
|
||||
const: null
|
||||
mutations:
|
||||
- op: add
|
||||
path: /livenessProbe
|
||||
value: {"exec": { "command": [ "cat", "/tmp/healthy" ] }, "initialDelaySeconds": 5, "periodSeconds": 5 }
|
||||
comment: "TODO: Change the livenessProbe setting to reflect your application's health"
|
||||
@@ -0,0 +1,32 @@
|
||||
successMessage: Memory limits are set
|
||||
failureMessage: Memory limits should be set
|
||||
category: Efficiency
|
||||
target: Container
|
||||
containers:
|
||||
exclude:
|
||||
- initContainer
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- resources
|
||||
properties:
|
||||
resources:
|
||||
type: object
|
||||
required:
|
||||
- limits
|
||||
properties:
|
||||
limits:
|
||||
type: object
|
||||
required:
|
||||
- memory
|
||||
properties:
|
||||
memory:
|
||||
type: string
|
||||
not:
|
||||
const: ''
|
||||
mutations:
|
||||
- op: add
|
||||
path: /resources/limits/memory
|
||||
value: "512Mi"
|
||||
comment: "TODO: Set this to the maximum amount of memory you want your workload to use"
|
||||
@@ -0,0 +1,32 @@
|
||||
successMessage: Memory requests are set
|
||||
failureMessage: Memory requests should be set
|
||||
category: Efficiency
|
||||
target: Container
|
||||
containers:
|
||||
exclude:
|
||||
- initContainer
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- resources
|
||||
properties:
|
||||
resources:
|
||||
type: object
|
||||
required:
|
||||
- requests
|
||||
properties:
|
||||
requests:
|
||||
type: object
|
||||
required:
|
||||
- memory
|
||||
properties:
|
||||
memory:
|
||||
type: string
|
||||
not:
|
||||
const: ''
|
||||
mutations:
|
||||
- op: add
|
||||
path: /resources/requests/memory
|
||||
value: "512Mi"
|
||||
comment: "TODO: Set this to the amount of Memory you want to reserve for your workload"
|
||||
@@ -0,0 +1,17 @@
|
||||
successMessage: Label app.kubernetes.io/name matches metadata.name
|
||||
failureMessage: Label app.kubernetes.io/name must match metadata.name
|
||||
target: Controller
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
required: ["labels"]
|
||||
properties:
|
||||
labels:
|
||||
type: object
|
||||
required: ["app.kubernetes.io/name"]
|
||||
properties:
|
||||
app.kubernetes.io/name:
|
||||
const: "{{ .metadata.name }}"
|
||||
@@ -0,0 +1,49 @@
|
||||
successMessage: A NetworkPolicy matches pod labels and contains egress and ingress rules
|
||||
failureMessage: A NetworkPolicy should match pod labels and contain applied egress and ingress rules
|
||||
category: Security
|
||||
target: PodTemplate
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
properties:
|
||||
labels:
|
||||
type: object
|
||||
minProperties: 1
|
||||
additionalSchemaStrings:
|
||||
networking.k8s.io/NetworkPolicy: |
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
required: ["podSelector", "egress", "ingress"]
|
||||
properties:
|
||||
podSelector:
|
||||
type: object
|
||||
required: ["matchLabels"]
|
||||
properties:
|
||||
matchLabels:
|
||||
type: object
|
||||
oneOf:
|
||||
{{ range $key, $value := .Polaris.PodTemplate.metadata.labels }}
|
||||
- properties:
|
||||
"{{ $key }}":
|
||||
type: string
|
||||
const: {{ $value }}
|
||||
required: ["{{ $key }}"]
|
||||
{{ end }}
|
||||
egress:
|
||||
type: array
|
||||
minItems: 1
|
||||
ingress:
|
||||
minItems: 1
|
||||
type: array
|
||||
policyTypes:
|
||||
type: array
|
||||
allOf:
|
||||
- contains:
|
||||
pattern: '^(?i)Egress$'
|
||||
- contains:
|
||||
pattern: '^(?i)Ingress$'
|
||||
@@ -0,0 +1,39 @@
|
||||
successMessage: A PodDisruptionBudget is attached
|
||||
failureMessage: Should have a PodDisruptionBudget
|
||||
category: Reliability
|
||||
target: Controller
|
||||
controllers:
|
||||
include:
|
||||
- Deployment
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
properties:
|
||||
labels:
|
||||
type: object
|
||||
minProperties: 1
|
||||
additionalSchemaStrings:
|
||||
policy/PodDisruptionBudget: |
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
required: ["selector"]
|
||||
properties:
|
||||
selector:
|
||||
type: object
|
||||
required: ["matchLabels"]
|
||||
properties:
|
||||
matchLabels:
|
||||
type: object
|
||||
anyOf:
|
||||
{{ range $key, $value := .metadata.labels }}
|
||||
- properties:
|
||||
"{{ $key }}":
|
||||
type: string
|
||||
const: {{ $value }}
|
||||
required: ["{{ $key }}"]
|
||||
{{ end }}
|
||||
@@ -0,0 +1,48 @@
|
||||
successMessage: Filesystem is read only
|
||||
failureMessage: Filesystem should be read only
|
||||
category: Security
|
||||
target: Container
|
||||
schemaTarget: PodSpec
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
definitions:
|
||||
goodSecurityContext:
|
||||
type: object
|
||||
anyOf:
|
||||
- required:
|
||||
- readOnlyRootFilesystem
|
||||
properties:
|
||||
readOnlyRootFilesystem:
|
||||
const: true
|
||||
notBadSecurityContext:
|
||||
type: object
|
||||
properties:
|
||||
readOnlyRootFilesystem:
|
||||
const: true
|
||||
type: object
|
||||
anyOf:
|
||||
- required:
|
||||
- securityContext
|
||||
properties:
|
||||
securityContext:
|
||||
$ref: "#/definitions/goodSecurityContext"
|
||||
containers:
|
||||
type: array
|
||||
items:
|
||||
properties:
|
||||
securityContext:
|
||||
$ref: "#/definitions/notBadSecurityContext"
|
||||
- properties:
|
||||
containers:
|
||||
type: array
|
||||
items:
|
||||
required:
|
||||
- securityContext
|
||||
properties:
|
||||
securityContext:
|
||||
$ref: "#/definitions/goodSecurityContext"
|
||||
mutations:
|
||||
- op: add
|
||||
path: /securityContext/readOnlyRootFilesystem
|
||||
value: true
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
successMessage: Voluntary evictions are possible
|
||||
failureMessage: Voluntary evictions are not possible
|
||||
category: Reliability
|
||||
target: policy/PodDisruptionBudget
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
properties:
|
||||
minAvailable:
|
||||
not:
|
||||
const: '100%'
|
||||
maxUnavailable:
|
||||
allOf:
|
||||
- not:
|
||||
const: 0
|
||||
- not:
|
||||
const: '0%'
|
||||
@@ -0,0 +1,13 @@
|
||||
successMessage: Priority class has been set
|
||||
failureMessage: Priority class should be set
|
||||
category: Security
|
||||
target: PodSpec
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- priorityClassName
|
||||
mutations:
|
||||
- op: add
|
||||
path: /priorityClassName
|
||||
value: high-priority
|
||||
@@ -0,0 +1,48 @@
|
||||
successMessage: Privilege escalation not allowed
|
||||
failureMessage: Privilege escalation should not be allowed
|
||||
category: Security
|
||||
target: Container
|
||||
schemaTarget: PodSpec
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
definitions:
|
||||
goodSecurityContext:
|
||||
type: object
|
||||
anyOf:
|
||||
- required:
|
||||
- allowPrivilegeEscalation
|
||||
properties:
|
||||
allowPrivilegeEscalation:
|
||||
const: false
|
||||
notBadSecurityContext:
|
||||
type: object
|
||||
properties:
|
||||
allowPrivilegeEscalation:
|
||||
const: false
|
||||
type: object
|
||||
anyOf:
|
||||
- required:
|
||||
- securityContext
|
||||
properties:
|
||||
securityContext:
|
||||
$ref: "#/definitions/goodSecurityContext"
|
||||
containers:
|
||||
type: array
|
||||
items:
|
||||
properties:
|
||||
securityContext:
|
||||
$ref: "#/definitions/notBadSecurityContext"
|
||||
- properties:
|
||||
containers:
|
||||
type: array
|
||||
items:
|
||||
required:
|
||||
- securityContext
|
||||
properties:
|
||||
securityContext:
|
||||
$ref: "#/definitions/goodSecurityContext"
|
||||
|
||||
mutations:
|
||||
- op: add
|
||||
path: /securityContext/allowPrivilegeEscalation
|
||||
value: false
|
||||
@@ -0,0 +1,15 @@
|
||||
successMessage: Image pull policy is "Always"
|
||||
failureMessage: Image pull policy should be "Always"
|
||||
category: Reliability
|
||||
target: Container
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
required:
|
||||
- imagePullPolicy
|
||||
properties:
|
||||
imagePullPolicy:
|
||||
const: Always
|
||||
mutations:
|
||||
- op: add
|
||||
path: /imagePullPolicy
|
||||
value: Always
|
||||
@@ -0,0 +1,26 @@
|
||||
successMessage: Readiness probe is configured
|
||||
failureMessage: Readiness probe should be configured
|
||||
category: Reliability
|
||||
controllers:
|
||||
exclude:
|
||||
- Job
|
||||
- CronJob
|
||||
containers:
|
||||
exclude:
|
||||
- initContainer
|
||||
target: Container
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- readinessProbe
|
||||
properties:
|
||||
readinessProbe:
|
||||
type: object
|
||||
not:
|
||||
const: null
|
||||
mutations:
|
||||
- op: add
|
||||
path: /readinessProbe
|
||||
value: {"exec": { "command": [ "cat", "/tmp/healthy" ] }, "initialDelaySeconds": 5, "periodSeconds": 5 }
|
||||
comment: "TODO: Change the readinessProbe setting to reflect your application's readiness to serve traffic"
|
||||
@@ -0,0 +1,56 @@
|
||||
successMessage: The Role does not allow pods/exec or pods/attach
|
||||
failureMessage: The Role allows Pods/exec or pods/attach
|
||||
category: Security
|
||||
target: rbac.authorization.k8s.io/Role
|
||||
schemaString: |
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required: ["metadata", "rules"]
|
||||
anyOf:
|
||||
# Do not alert on default Roles.
|
||||
- properties:
|
||||
metadata:
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
anyOf:
|
||||
- pattern: '^system:'
|
||||
- const: "gce:podsecuritypolicy:calico-sa"
|
||||
- properties:
|
||||
metadata:
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
rules:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
not:
|
||||
required: ["apiGroups", "resources", "verbs"]
|
||||
properties:
|
||||
apiGroups:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: ""
|
||||
- const: '*'
|
||||
resources:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: '*'
|
||||
- const: "pods/exec"
|
||||
- const: "pods/attach"
|
||||
verbs:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: '*'
|
||||
# An exec is also possible by `get`ing a web socket.
|
||||
- const: 'get'
|
||||
- const: 'create'
|
||||
@@ -0,0 +1,98 @@
|
||||
successMessage: The RoleBinding does not reference the default cluster-admin ClusterRole or one with wildcard permissions
|
||||
failureMessage: The RoleBinding references the default cluster-admin ClusterRole or one with wildcard permissions
|
||||
category: Security
|
||||
target: rbac.authorization.k8s.io/RoleBinding
|
||||
schemaString: |
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
anyOf:
|
||||
# Pass RoleBindings that point to a Role.
|
||||
- required: ["roleRef"]
|
||||
properties:
|
||||
roleRef:
|
||||
required: ["kind"]
|
||||
properties:
|
||||
kind:
|
||||
type: string
|
||||
const: "Role"
|
||||
# Do not alert on default ClusterRoleBindings.
|
||||
- required: ["metadata"]
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
anyOf:
|
||||
- pattern: '^system:'
|
||||
- const: "gce:podsecuritypolicy:calico-sa"
|
||||
- required: ["roleRef"]
|
||||
properties:
|
||||
roleRef:
|
||||
required: ["apiGroup", "kind", "name"]
|
||||
properties:
|
||||
apiGroup:
|
||||
type: string
|
||||
const: "rbac.authorization.k8s.io"
|
||||
kind:
|
||||
type: string
|
||||
const: "ClusterRole"
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
not:
|
||||
const: "cluster-admin"
|
||||
additionalSchemaStrings:
|
||||
rbac.authorization.k8s.io/ClusterRole: |
|
||||
type: object
|
||||
# This schema is validated for all roleBindings, regardless of their roleRef.
|
||||
{{ if eq .roleRef.kind "ClusterRole" }}
|
||||
{{ if and (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
|
||||
required: ["metadata", "rules"]
|
||||
allOf:
|
||||
- properties:
|
||||
metadata:
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
const: "{{ .roleRef.name }}"
|
||||
- properties:
|
||||
rules:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
not:
|
||||
required: ["apiGroups", "resources", "verbs"]
|
||||
properties:
|
||||
apiGroups:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
const: "*"
|
||||
resources:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
const: '*'
|
||||
verbs:
|
||||
type: array
|
||||
uniqueItems: true
|
||||
oneOf:
|
||||
- contains:
|
||||
type: string
|
||||
const: '*'
|
||||
- minItems: 7
|
||||
items:
|
||||
type: string
|
||||
enum:
|
||||
- "get"
|
||||
- "list"
|
||||
- "watch"
|
||||
- "create"
|
||||
- "update"
|
||||
- "patch"
|
||||
- "delete"
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
@@ -0,0 +1,96 @@
|
||||
successMessage: The RoleBinding does not reference a Role with wildcard permissions
|
||||
failureMessage: The RoleBinding references a Role with wildcard permissions
|
||||
category: Security
|
||||
target: rbac.authorization.k8s.io/RoleBinding
|
||||
schemaString: |
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
anyOf:
|
||||
# Pass RoleBindings that point to a ClusterRole.
|
||||
- required: ["roleRef"]
|
||||
properties:
|
||||
roleRef:
|
||||
required: ["kind"]
|
||||
properties:
|
||||
kind:
|
||||
type: string
|
||||
const: "ClusterRole"
|
||||
# Do not alert on default RoleBindings.
|
||||
- required: ["metadata"]
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
anyOf:
|
||||
- pattern: '^system:'
|
||||
- const: "gce:podsecuritypolicy:calico-sa"
|
||||
- required: ["roleRef"]
|
||||
properties:
|
||||
roleRef:
|
||||
required: ["apiGroup", "kind", "name"]
|
||||
properties:
|
||||
apiGroup:
|
||||
type: string
|
||||
const: "rbac.authorization.k8s.io"
|
||||
kind:
|
||||
type: string
|
||||
const: "Role"
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
additionalSchemaStrings:
|
||||
rbac.authorization.k8s.io/Role: |
|
||||
type: object
|
||||
# This schema is validated for all roleBindings, regardless of their roleRef.
|
||||
{{ if eq .roleRef.kind "Role" }}
|
||||
{{ if and (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
|
||||
required: ["metadata", "rules"]
|
||||
allOf:
|
||||
- properties:
|
||||
metadata:
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
const: "{{ .roleRef.name }}"
|
||||
- properties:
|
||||
rules:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
not:
|
||||
required: ["apiGroups", "resources", "verbs"]
|
||||
properties:
|
||||
apiGroups:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
const: "*"
|
||||
resources:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
const: '*'
|
||||
verbs:
|
||||
type: array
|
||||
uniqueItems: true
|
||||
oneOf:
|
||||
- contains:
|
||||
type: string
|
||||
const: '*'
|
||||
- minItems: 7
|
||||
items:
|
||||
type: string
|
||||
enum:
|
||||
- "get"
|
||||
- "list"
|
||||
- "watch"
|
||||
- "create"
|
||||
- "update"
|
||||
- "patch"
|
||||
- "delete"
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
@@ -0,0 +1,92 @@
|
||||
successMessage: The RoleBinding does not reference a ClusterRole allowing pods/exec or pods/attach
|
||||
failureMessage: The RoleBinding references a ClusterRole that allows Pods/exec, allows pods/attach, or that does not exist
|
||||
category: Security
|
||||
target: rbac.authorization.k8s.io/RoleBinding
|
||||
schemaString: |
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
anyOf:
|
||||
# Pass RoleBindings that point to a Role.
|
||||
- required: ["roleRef"]
|
||||
properties:
|
||||
roleRef:
|
||||
required: ["kind"]
|
||||
properties:
|
||||
kind:
|
||||
type: string
|
||||
const: "Role"
|
||||
# Do not alert on default RoleBindings.
|
||||
- required: ["metadata"]
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
anyOf:
|
||||
- pattern: '^system:'
|
||||
- const: "gce:podsecuritypolicy:calico-sa"
|
||||
- required: ["roleRef"]
|
||||
properties:
|
||||
roleRef:
|
||||
required: ["apiGroup", "kind", "name"]
|
||||
properties:
|
||||
apiGroup:
|
||||
type: string
|
||||
const: "rbac.authorization.k8s.io"
|
||||
kind:
|
||||
type: string
|
||||
const: "ClusterRole"
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
additionalSchemaStrings:
|
||||
rbac.authorization.k8s.io/ClusterRole: |
|
||||
type: object
|
||||
# This schema is validated for all roleBindings, regardless of their roleRef.
|
||||
{{ if eq .roleRef.kind "ClusterRole" }}
|
||||
{{ if and (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
|
||||
required: ["metadata", "rules"]
|
||||
allOf:
|
||||
- properties:
|
||||
metadata:
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
const: "{{ .roleRef.name }}"
|
||||
- properties:
|
||||
rules:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
not:
|
||||
required: ["apiGroups", "resources", "verbs"]
|
||||
properties:
|
||||
apiGroups:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: ""
|
||||
- const: '*'
|
||||
resources:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: '*'
|
||||
- const: "pods/exec"
|
||||
- const: "pods/attach"
|
||||
verbs:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: '*'
|
||||
# An exec is also possible by `get`ing a web socket.
|
||||
- const: 'get'
|
||||
- const: 'create'
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
@@ -0,0 +1,95 @@
|
||||
successMessage: The RoleBinding does not reference a Role allowing Pod exec or attach
|
||||
failureMessage: The RoleBinding references a Role that allows Pods/exec, allows pods/attach, or that does not exist
|
||||
category: Security
|
||||
target: rbac.authorization.k8s.io/RoleBinding
|
||||
schemaString: |
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
anyOf:
|
||||
# Pass RoleBindings that point to a ClusterRole.
|
||||
- required: ["roleRef"]
|
||||
properties:
|
||||
roleRef:
|
||||
required: ["apiGroup", "kind", "name"]
|
||||
properties:
|
||||
apiGroup:
|
||||
type: string
|
||||
const: "rbac.authorization.k8s.io"
|
||||
kind:
|
||||
type: string
|
||||
const: "Role"
|
||||
# Do not alert on default RoleBindings.
|
||||
- required: ["metadata"]
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
anyOf:
|
||||
- pattern: '^system:'
|
||||
- const: "gce:podsecuritypolicy:calico-sa"
|
||||
- required: ["roleRef"]
|
||||
properties:
|
||||
roleRef:
|
||||
required: ["apiGroup", "kind", "name"]
|
||||
properties:
|
||||
apiGroup:
|
||||
type: string
|
||||
const: "rbac.authorization.k8s.io"
|
||||
kind:
|
||||
type: string
|
||||
const: "Role"
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
additionalSchemaStrings:
|
||||
rbac.authorization.k8s.io/Role: |
|
||||
type: object
|
||||
# This schema is validated for all roleBindings, regardless of their roleRef.
|
||||
{{ if eq .roleRef.kind "Role" }}
|
||||
{{ if and (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
|
||||
required: ["metadata", "rules"]
|
||||
allOf:
|
||||
- properties:
|
||||
metadata:
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
const: "{{ .roleRef.name }}"
|
||||
- properties:
|
||||
rules:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
not:
|
||||
required: ["apiGroups", "resources", "verbs"]
|
||||
properties:
|
||||
apiGroups:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: ""
|
||||
- const: '*'
|
||||
resources:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: '*'
|
||||
- const: "pods/exec"
|
||||
- const: "pods/attach"
|
||||
verbs:
|
||||
type: array
|
||||
contains:
|
||||
type: string
|
||||
anyOf:
|
||||
- const: '*'
|
||||
# An exec is also possible by `get`ing a web socket.
|
||||
- const: 'get'
|
||||
- const: 'create'
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
@@ -0,0 +1,28 @@
|
||||
successMessage: Not running as privileged
|
||||
failureMessage: Should not be running as privileged
|
||||
category: Security
|
||||
target: Container
|
||||
schemaTarget: PodSpec
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
definitions:
|
||||
notBadSecurityContext:
|
||||
type: object
|
||||
properties:
|
||||
privileged:
|
||||
not:
|
||||
const: true
|
||||
type: object
|
||||
properties:
|
||||
securityContext:
|
||||
$ref: "#/definitions/notBadSecurityContext"
|
||||
containers:
|
||||
type: array
|
||||
items:
|
||||
properties:
|
||||
securityContext:
|
||||
$ref: "#/definitions/notBadSecurityContext"
|
||||
mutations:
|
||||
- op: add
|
||||
path: /securityContext/privileged
|
||||
value: false
|
||||
@@ -0,0 +1,56 @@
|
||||
successMessage: Is not allowed to run as root
|
||||
failureMessage: Should not be allowed to run as root
|
||||
category: Security
|
||||
target: Container
|
||||
schemaTarget: PodSpec
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
definitions:
|
||||
goodSecurityContext:
|
||||
type: object
|
||||
anyOf:
|
||||
- required:
|
||||
- runAsUser
|
||||
properties:
|
||||
runAsUser:
|
||||
minimum: 1
|
||||
- required:
|
||||
- runAsNonRoot
|
||||
properties:
|
||||
runAsNonRoot:
|
||||
const: true
|
||||
notBadSecurityContext:
|
||||
type: object
|
||||
properties:
|
||||
runAsUser:
|
||||
minimum: 1
|
||||
runAsNonRoot:
|
||||
const: true
|
||||
type: object
|
||||
anyOf:
|
||||
# non-root specified at pod-level, and not overridden at container level
|
||||
- required:
|
||||
- securityContext
|
||||
properties:
|
||||
securityContext:
|
||||
$ref: "#/definitions/goodSecurityContext"
|
||||
containers:
|
||||
type: array
|
||||
items:
|
||||
properties:
|
||||
securityContext:
|
||||
$ref: "#/definitions/notBadSecurityContext"
|
||||
# non-root specified at container level
|
||||
- properties:
|
||||
containers:
|
||||
type: array
|
||||
items:
|
||||
required:
|
||||
- securityContext
|
||||
properties:
|
||||
securityContext:
|
||||
$ref: "#/definitions/goodSecurityContext"
|
||||
mutations:
|
||||
- op: add
|
||||
path: /securityContext/runAsNonRoot
|
||||
value: true
|
||||
@@ -0,0 +1,43 @@
|
||||
successMessage: The ConfigMap does not contain potentially sensitive content in its keys and values
|
||||
failureMessage: Potentially sensitive content is detected in the ConfigMap keys or values
|
||||
category: Security
|
||||
target: /ConfigMap
|
||||
schemaString: |
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required: ["metadata"]
|
||||
properties:
|
||||
metadata:
|
||||
required: ["name"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
data:
|
||||
type: object
|
||||
propertyNames:
|
||||
'$comment': These ConfigMap keys will be disallowed.
|
||||
allOf:
|
||||
- not:
|
||||
pattern: '(?i)^AWS_SECRET_ACCESS_KEY$'
|
||||
- not:
|
||||
pattern: '(?i)^GOOGLE_APPLICATION_CREDENTIALS$'
|
||||
- not:
|
||||
pattern: '(?i)^AZURE_.+KEY$'
|
||||
- not:
|
||||
pattern: '(?i)^OCI_CLI_KEY_CONTENT$'
|
||||
- not:
|
||||
pattern: '(?i)password'
|
||||
- not:
|
||||
pattern: '(?i)token'
|
||||
- not:
|
||||
pattern: '(?i)bearer'
|
||||
- not:
|
||||
pattern: '(?i)secret'
|
||||
'$comment': This allows ConfigMap keys not excluded above.
|
||||
- pattern: '(?i).*'
|
||||
additionalProperties:
|
||||
'$comment': These ConfigMap values will be disallowed.
|
||||
allOf:
|
||||
- not:
|
||||
'$comment': THis matches variations like begin private key, begin rsa private key ...
|
||||
pattern: '(?i)\s*-BEGIN\s+.*PRIVATE KEY-\s*'
|
||||
@@ -0,0 +1,50 @@
|
||||
successMessage: The container does not set potentially sensitive environment variables
|
||||
failureMessage: The container sets potentially sensitive environment variables
|
||||
category: Security
|
||||
target: Container
|
||||
schemaString: |
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
properties:
|
||||
env:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
oneOf:
|
||||
- required: ["name", "value"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
'$comment': These environment variable names will be disallowed.
|
||||
allOf:
|
||||
- not:
|
||||
pattern: '(?i)^AWS_SECRET_ACCESS_KEY$'
|
||||
- not:
|
||||
pattern: '(?i)^GOOGLE_APPLICATION_CREDENTIALS$'
|
||||
- not:
|
||||
pattern: '(?i)^AZURE_.+KEY$'
|
||||
- not:
|
||||
pattern: '(?i)^OCI_CLI_KEY_CONTENT$'
|
||||
- not:
|
||||
pattern: '(?i)password'
|
||||
- not:
|
||||
pattern: '(?i)token'
|
||||
- not:
|
||||
pattern: '(?i)bearer'
|
||||
- not:
|
||||
pattern: '(?i)secret'
|
||||
'$comment': This allows variable names not excluded above.
|
||||
- pattern: '(?i).*'
|
||||
value:
|
||||
type: string
|
||||
'$comment': These environment variable values will be disallowed.
|
||||
allOf:
|
||||
- not:
|
||||
'$comment': THis matches variations like begin private key, begin rsa private key ...
|
||||
pattern: '(?i)\s*-BEGIN\s+.*PRIVATE KEY-\s*'
|
||||
- required: ["name", "valueFrom"]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
valueFrom:
|
||||
type: object
|
||||
@@ -0,0 +1,16 @@
|
||||
successMessage: Image tag is specified
|
||||
failureMessage: Image tag should be specified
|
||||
category: Reliability
|
||||
target: Container
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
required:
|
||||
- image
|
||||
allOf:
|
||||
- properties:
|
||||
image:
|
||||
pattern: ^.+:.+$
|
||||
- properties:
|
||||
image:
|
||||
not:
|
||||
pattern: ^.+:latest$
|
||||
@@ -0,0 +1,19 @@
|
||||
successMessage: Ingress has TLS configured
|
||||
failureMessage: Ingress does not have TLS configured
|
||||
category: Security
|
||||
target: networking.k8s.io/Ingress
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
required:
|
||||
- tls
|
||||
properties:
|
||||
tls:
|
||||
type: array
|
||||
not:
|
||||
const: null
|
||||
@@ -0,0 +1,21 @@
|
||||
successMessage: Pod has a valid topology spread constraint
|
||||
failureMessage: Pod should be configured with a valid topology spread constraint
|
||||
category: Reliability
|
||||
target: PodSpec
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- topologySpreadConstraints
|
||||
properties:
|
||||
topologySpreadConstraints:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
topologyKey:
|
||||
anyOf:
|
||||
- type: string
|
||||
const: "kubernetes.io/hostname"
|
||||
- type: string
|
||||
const: "topology.kubernetes.io/zone"
|
||||
@@ -0,0 +1,240 @@
|
||||
// Copyright 2020 FairwindsOps Inc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
cfg "github.com/fairwindsops/polaris/pkg/config"
|
||||
"github.com/fairwindsops/polaris/pkg/kube"
|
||||
"github.com/fairwindsops/polaris/pkg/validator"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
var (
|
||||
setExitCode bool
|
||||
onlyShowFailedTests bool
|
||||
minScore int
|
||||
auditOutputURL string
|
||||
auditOutputFile string
|
||||
auditOutputFormat string
|
||||
resourceToAudit string
|
||||
useColor bool
|
||||
helmChart string
|
||||
helmValues string
|
||||
checks []string
|
||||
auditNamespace string
|
||||
skipSslValidation bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(auditCmd)
|
||||
auditCmd.PersistentFlags().StringVar(&auditPath, "audit-path", "", "If specified, audits one or more YAML files instead of a cluster.")
|
||||
auditCmd.PersistentFlags().BoolVar(&setExitCode, "set-exit-code-on-danger", false, "Set an exit code of 3 when the audit contains danger-level issues.")
|
||||
auditCmd.PersistentFlags().BoolVar(&onlyShowFailedTests, "only-show-failed-tests", false, "If specified, audit output will only show failed tests.")
|
||||
auditCmd.PersistentFlags().IntVar(&minScore, "set-exit-code-below-score", 0, "Set an exit code of 4 when the score is below this threshold (1-100).")
|
||||
auditCmd.PersistentFlags().StringVar(&auditOutputURL, "output-url", "", "Destination URL to send audit results.")
|
||||
auditCmd.PersistentFlags().StringVar(&auditOutputFile, "output-file", "", "Destination file for audit results.")
|
||||
auditCmd.PersistentFlags().StringVarP(&auditOutputFormat, "format", "f", "json", "Output format for results - json, yaml, pretty, or score.")
|
||||
auditCmd.PersistentFlags().BoolVar(&useColor, "color", true, "Whether to use color in pretty format.")
|
||||
auditCmd.PersistentFlags().StringVar(&displayName, "display-name", "", "An optional identifier for the audit.")
|
||||
auditCmd.PersistentFlags().StringVar(&resourceToAudit, "resource", "", "Audit a specific resource, in the format namespace/kind/version/name, e.g. nginx-ingress/Deployment.apps/v1/default-backend.")
|
||||
auditCmd.PersistentFlags().StringVar(&helmChart, "helm-chart", "", "Will fill out Helm template")
|
||||
auditCmd.PersistentFlags().StringVar(&helmValues, "helm-values", "", "Optional flag to add helm values")
|
||||
auditCmd.PersistentFlags().StringSliceVar(&checks, "checks", []string{}, "Optional flag to specify specific checks to check")
|
||||
auditCmd.PersistentFlags().StringVar(&auditNamespace, "namespace", "", "Namespace to audit. Only applies to in-cluster audits")
|
||||
auditCmd.PersistentFlags().BoolVar(&skipSslValidation, "skip-ssl-validation", false, "Skip https certificate verification")
|
||||
}
|
||||
|
||||
var auditCmd = &cobra.Command{
|
||||
Use: "audit",
|
||||
Short: "Runs a one-time audit.",
|
||||
Long: `Runs a one-time audit.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if displayName != "" {
|
||||
config.DisplayName = displayName
|
||||
}
|
||||
if len(checks) > 0 {
|
||||
targetChecks := make(map[string]bool)
|
||||
for _, check := range checks {
|
||||
targetChecks[check] = true
|
||||
}
|
||||
for key := range config.Checks {
|
||||
if isTarget := targetChecks[key]; !isTarget {
|
||||
config.Checks[key] = cfg.SeverityIgnore
|
||||
}
|
||||
}
|
||||
}
|
||||
if auditNamespace != "" {
|
||||
if helmChart != "" {
|
||||
logrus.Warn("--namespace and --helm-chart are mutually exclusive. --namespace will be ignored.")
|
||||
}
|
||||
if auditPath != "" {
|
||||
logrus.Warn("--namespace and --audit-path are mutually exclusive. --namespace will be ignored.")
|
||||
}
|
||||
config.Namespace = auditNamespace
|
||||
}
|
||||
if helmChart != "" {
|
||||
var err error
|
||||
auditPath, err = ProcessHelmTemplates(helmChart, helmValues)
|
||||
if err != nil {
|
||||
logrus.Infof("Couldn't process helm chart: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
k, err := kube.CreateResourceProvider(context.TODO(), auditPath, resourceToAudit, config)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error fetching Kubernetes resources %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
auditData, err := validator.RunAudit(config, k)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while running audit on resources: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
outputAudit(auditData, auditOutputFile, auditOutputURL, auditOutputFormat, useColor, onlyShowFailedTests)
|
||||
|
||||
summary := auditData.GetSummary()
|
||||
score := summary.GetScore()
|
||||
if setExitCode && summary.Dangers > 0 {
|
||||
logrus.Infof("%d danger items found in audit", summary.Dangers)
|
||||
os.Exit(3)
|
||||
} else if minScore != 0 && score < uint(minScore) {
|
||||
logrus.Infof("Audit score of %d is less than the provided minimum of %d", score, minScore)
|
||||
os.Exit(4)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// ProcessHelmTemplates turns helm into yaml to be processed by Polaris or the other tools.
|
||||
func ProcessHelmTemplates(helmChart, helmValues string) (string, error) {
|
||||
cmd := exec.Command("helm", "dependency", "update", helmChart)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
logrus.Error(string(output))
|
||||
return "", err
|
||||
}
|
||||
|
||||
dir, err := os.MkdirTemp("", "*")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
params := []string{
|
||||
"template", helmChart,
|
||||
"--generate-name",
|
||||
"--output-dir",
|
||||
dir,
|
||||
}
|
||||
if helmValues != "" {
|
||||
params = append(params, "--values", helmValues)
|
||||
}
|
||||
|
||||
cmd = exec.Command("helm", params...)
|
||||
output, err = cmd.CombinedOutput()
|
||||
|
||||
if err != nil {
|
||||
logrus.Error(string(output))
|
||||
return "", err
|
||||
}
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
func outputAudit(auditData validator.AuditData, outputFile, outputURL, outputFormat string, useColor bool, onlyShowFailedTests bool) {
|
||||
if onlyShowFailedTests {
|
||||
auditData = auditData.RemoveSuccessfulResults()
|
||||
}
|
||||
var outputBytes []byte
|
||||
var err error
|
||||
if outputFormat == "score" {
|
||||
outputBytes = []byte(fmt.Sprintf("%d\n", auditData.GetSummary().GetScore()))
|
||||
} else if outputFormat == "yaml" {
|
||||
var jsonBytes []byte
|
||||
jsonBytes, err = json.Marshal(auditData)
|
||||
if err == nil {
|
||||
outputBytes, err = yaml.JSONToYAML(jsonBytes)
|
||||
}
|
||||
} else if outputFormat == "pretty" {
|
||||
outputBytes = []byte(auditData.GetPrettyOutput(useColor))
|
||||
} else {
|
||||
outputBytes, err = json.MarshalIndent(auditData, "", " ")
|
||||
}
|
||||
if err != nil {
|
||||
logrus.Errorf("Error marshalling audit: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if outputURL == "" && outputFile == "" {
|
||||
os.Stdout.Write(outputBytes)
|
||||
} else {
|
||||
if outputURL != "" {
|
||||
req, err := http.NewRequest("POST", outputURL, bytes.NewBuffer(outputBytes))
|
||||
|
||||
if err != nil {
|
||||
logrus.Errorf("Error building request for output: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if outputFormat == "json" {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
} else if outputFormat == "yaml" {
|
||||
req.Header.Set("Content-Type", "application/x-yaml")
|
||||
} else {
|
||||
req.Header.Set("Content-Type", "text/plain")
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
if skipSslValidation {
|
||||
transport := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
|
||||
client = &http.Client{Transport: transport}
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error making request for output: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
logrus.Errorf("Error reading response: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
logrus.Infof("Received response: %v", body)
|
||||
}
|
||||
|
||||
if outputFile != "" {
|
||||
err := os.WriteFile(outputFile, outputBytes, 0644)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error writing output to file: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright 2020 FairwindsOps Inc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/fairwindsops/polaris/pkg/dashboard"
|
||||
"github.com/fairwindsops/polaris/pkg/validator"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var serverPort int
|
||||
var basePath string
|
||||
var loadAuditFile string
|
||||
var listeningAddress string
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(dashboardCmd)
|
||||
dashboardCmd.PersistentFlags().IntVarP(&serverPort, "port", "p", 8080, "Port for the dashboard webserver.")
|
||||
dashboardCmd.PersistentFlags().StringVar(&listeningAddress, "listening-address", "", "Listening Address for the dashboard webserver.")
|
||||
dashboardCmd.PersistentFlags().StringVar(&basePath, "base-path", "/", "Path on which the dashboard is served.")
|
||||
dashboardCmd.PersistentFlags().StringVar(&loadAuditFile, "load-audit-file", "", "Runs the dashboard with data saved from a past audit.")
|
||||
dashboardCmd.PersistentFlags().StringVar(&auditPath, "audit-path", "", "If specified, audits one or more YAML files instead of a cluster.")
|
||||
dashboardCmd.PersistentFlags().StringVar(&displayName, "display-name", "", "An optional identifier for the audit.")
|
||||
|
||||
}
|
||||
|
||||
var dashboardCmd = &cobra.Command{
|
||||
Use: "dashboard",
|
||||
Short: "Runs the webserver for Polaris dashboard.",
|
||||
Long: `Runs the webserver for Polaris dashboard.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if displayName != "" {
|
||||
config.DisplayName = displayName
|
||||
}
|
||||
|
||||
var auditDataPtr *validator.AuditData
|
||||
if loadAuditFile != "" {
|
||||
auditData := validator.ReadAuditFromFile(loadAuditFile)
|
||||
auditDataPtr = &auditData
|
||||
}
|
||||
router := dashboard.GetRouter(config, auditPath, serverPort, basePath, auditDataPtr)
|
||||
router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("OK"))
|
||||
})
|
||||
http.Handle("/", router)
|
||||
|
||||
logrus.Infof("Starting Polaris dashboard server on port %d", serverPort)
|
||||
logrus.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", listeningAddress, serverPort), nil))
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
// Copyright 2020 FairwindsOps Inc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/fairwindsops/polaris/pkg/kube"
|
||||
"github.com/fairwindsops/polaris/pkg/mutation"
|
||||
"github.com/fairwindsops/polaris/pkg/validator"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const templateLineMarker = "# POLARIS_FIX_TMPL"
|
||||
const templateOpenMarker = "POLARIS_OPEN_TMPL"
|
||||
const templateCloseMarker = "POLARIS_CLOSE_TMPL"
|
||||
|
||||
var (
|
||||
filesPath string
|
||||
checksToFix []string
|
||||
fixAll bool
|
||||
isTemplate bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(fixCommand)
|
||||
fixCommand.PersistentFlags().StringVar(&filesPath, "files-path", "", "mutate and fix one or more YAML files in a specified folder")
|
||||
fixCommand.PersistentFlags().BoolVar(&isTemplate, "template", false, "set to true when modifyng a YAML template, like a Helm chart (experimental)")
|
||||
fixCommand.PersistentFlags().StringSliceVar(&checksToFix, "checks", []string{}, "Optional flag to specify specific checks to fix eg. checks=hostIPCSet,hostPIDSet and checks=all applies fix to all defined checks mutations")
|
||||
}
|
||||
|
||||
var fixCommand = &cobra.Command{
|
||||
Use: "fix",
|
||||
Short: "Fix Infrastructure as code files.",
|
||||
Long: `Fix Infrastructure as code files.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
logrus.Debug("Setting up controller manager")
|
||||
|
||||
if filesPath == "" {
|
||||
logrus.Error("Please specify a files-path flag")
|
||||
cmd.Help()
|
||||
os.Exit(1)
|
||||
}
|
||||
var yamlFiles []string
|
||||
fileInfo, err := os.Stat(filesPath)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if fileInfo.IsDir() {
|
||||
baseDir := filesPath
|
||||
if !strings.HasSuffix(filesPath, "/") {
|
||||
baseDir = baseDir + "/"
|
||||
}
|
||||
yamlFiles, err = getYamlFiles(baseDir)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
yamlFiles = append(yamlFiles, filesPath)
|
||||
}
|
||||
|
||||
if len(checksToFix) > 0 {
|
||||
if len(checksToFix) == 1 && checksToFix[0] == "all" {
|
||||
allchecks := []string{}
|
||||
for key := range config.Checks {
|
||||
allchecks = append(allchecks, key)
|
||||
}
|
||||
config.Mutations = allchecks
|
||||
} else if len(checksToFix) == 0 && checksToFix[0] == "none" {
|
||||
config.Mutations = nil
|
||||
} else {
|
||||
config.Mutations = checksToFix
|
||||
}
|
||||
}
|
||||
|
||||
for _, fullFilePath := range yamlFiles {
|
||||
yamlContent, err := os.ReadFile(fullFilePath)
|
||||
if err != nil {
|
||||
logrus.Fatalf("Error reading file with file path %s: %v", fullFilePath, err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logrus.Fatalf("Error marshalling %s: %v", fullFilePath, err)
|
||||
}
|
||||
|
||||
if isTemplate {
|
||||
yamlContent = []byte(detemplate(string(yamlContent)))
|
||||
}
|
||||
kubeResources := kube.CreateResourceProviderFromYaml(string(yamlContent))
|
||||
results, err := validator.ApplyAllSchemaChecksToResourceProvider(&config, kubeResources)
|
||||
if err != nil {
|
||||
logrus.Fatalf("Error applying schema check to the resources %s: %v", fullFilePath, err)
|
||||
}
|
||||
allMutations := mutation.GetMutationsFromResults(results)
|
||||
|
||||
updatedYamlContent := ""
|
||||
if len(allMutations) > 0 {
|
||||
for _, resource := range kubeResources.Resources {
|
||||
key := fmt.Sprintf("%s/%s/%s", resource.Kind, resource.Resource.GetName(), resource.Resource.GetNamespace())
|
||||
fmt.Println("resource", key)
|
||||
mutations := allMutations[key]
|
||||
mutatedYamlContent, err := mutation.ApplyAllMutations(string(resource.OriginalObjectYAML), mutations)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error applying schema mutations to the resource %s: %v", key, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if updatedYamlContent != "" {
|
||||
updatedYamlContent += "\n---\n"
|
||||
}
|
||||
updatedYamlContent += mutatedYamlContent
|
||||
}
|
||||
}
|
||||
|
||||
if isTemplate {
|
||||
updatedYamlContent = retemplate(updatedYamlContent)
|
||||
}
|
||||
|
||||
if updatedYamlContent != "" {
|
||||
err = os.WriteFile(fullFilePath, []byte(updatedYamlContent), 0644)
|
||||
if err != nil {
|
||||
logrus.Fatalf("Error writing output to file: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
func detemplate(content string) string {
|
||||
lines := strings.Split(content, "\n")
|
||||
for idx, line := range lines {
|
||||
lines[idx] = detemplateLine(line)
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func retemplate(content string) string {
|
||||
lines := strings.Split(content, "\n")
|
||||
for idx, line := range lines {
|
||||
lines[idx] = retemplateLine(line)
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func detemplateLine(line string) string {
|
||||
if !strings.HasPrefix(strings.TrimSpace(line), "{{") {
|
||||
line = strings.ReplaceAll(line, "{", templateOpenMarker)
|
||||
line = strings.ReplaceAll(line, "}", templateCloseMarker)
|
||||
return line
|
||||
}
|
||||
tmplStart := strings.Index(line, "{{")
|
||||
newLine := line[:tmplStart] + templateLineMarker + line[tmplStart:]
|
||||
return newLine
|
||||
}
|
||||
|
||||
func retemplateLine(line string) string {
|
||||
if !strings.Contains(line, templateLineMarker) {
|
||||
line = strings.ReplaceAll(line, templateOpenMarker, "{")
|
||||
line = strings.ReplaceAll(line, templateCloseMarker, "}")
|
||||
return line
|
||||
}
|
||||
return strings.Replace(line, templateLineMarker, "", 1)
|
||||
}
|
||||
|
||||
func getYamlFiles(rootpath string) ([]string, error) {
|
||||
var list []string
|
||||
err := filepath.Walk(rootpath, func(path string, info os.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if filepath.Ext(path) == ".yaml" || filepath.Ext(path) == ".yml" {
|
||||
list = append(list, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return list, err
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
// Copyright 2020 FairwindsOps Inc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
conf "github.com/fairwindsops/polaris/pkg/config"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var configPath string
|
||||
var disallowExemptions, disallowConfigExemptions, disallowAnnotationExemptions, fixChecks bool
|
||||
var logLevel string
|
||||
var auditPath string
|
||||
var displayName string
|
||||
var kubeContext string
|
||||
|
||||
var (
|
||||
version string
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Flags
|
||||
rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "Location of Polaris configuration file.")
|
||||
rootCmd.PersistentFlags().StringVarP(&kubeContext, "context", "x", "", "Set the kube context.")
|
||||
rootCmd.PersistentFlags().BoolVarP(&disallowExemptions, "disallow-exemptions", "", false, "Disallow any configured exemption.")
|
||||
rootCmd.PersistentFlags().BoolVarP(&disallowConfigExemptions, "disallow-config-exemptions", "", false, "Disallow exemptions set within the configuration file.")
|
||||
rootCmd.PersistentFlags().BoolVarP(&disallowAnnotationExemptions, "disallow-annotation-exemptions", "", false, "Disallow any exemption defined as a controller annotation.")
|
||||
rootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "", logrus.InfoLevel.String(), "Logrus log level to be output (trace, debug, info, warning, error, fatal, panic).")
|
||||
}
|
||||
|
||||
var config conf.Configuration
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "polaris",
|
||||
Short: "polaris",
|
||||
Long: `Validation of best practices in your Kubernetes clusters.`,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
parsedLevel, err := logrus.ParseLevel(logLevel)
|
||||
if err != nil {
|
||||
logrus.Errorf("log-level flag has invalid value %s", logLevel)
|
||||
} else {
|
||||
logrus.SetLevel(parsedLevel)
|
||||
}
|
||||
|
||||
config, err = conf.ParseFile(configPath)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error parsing config at %s: %v", configPath, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
config.DisallowExemptions = disallowExemptions
|
||||
config.DisallowConfigExemptions = disallowConfigExemptions
|
||||
config.DisallowAnnotationExemptions = disallowAnnotationExemptions
|
||||
config.KubeContext = kubeContext
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
logrus.Error("You must specify a sub-command.")
|
||||
err := cmd.Help()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
os.Exit(1)
|
||||
},
|
||||
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
||||
os.Stderr.WriteString("\n\nWant more? Automate Polaris for free with Fairwinds Insights!\n🚀 https://fairwinds.com/insights-signup/polaris 🚀 \n")
|
||||
},
|
||||
}
|
||||
|
||||
// Execute the stuff
|
||||
func Execute(VERSION string) {
|
||||
version = VERSION
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
logrus.Error(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2020 FairwindsOps Inc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
}
|
||||
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Prints the current version.",
|
||||
Long: `Prints the current version of the tool.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("Polaris version:" + version)
|
||||
},
|
||||
PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright 2020 FairwindsOps Inc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
fwebhook "github.com/fairwindsops/polaris/pkg/webhook"
|
||||
k8sConfig "sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
|
||||
)
|
||||
|
||||
var webhookPort int
|
||||
var disableWebhookConfigInstaller bool
|
||||
var enableMutations bool
|
||||
var enableValidations bool
|
||||
var certDir string
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(webhookCmd)
|
||||
webhookCmd.PersistentFlags().IntVarP(&webhookPort, "port", "p", 9876, "Port for the dashboard webserver.")
|
||||
webhookCmd.PersistentFlags().BoolVar(&disableWebhookConfigInstaller, "disable-webhook-config-installer", false, "Disable the installer in the webhook server, so it won't install webhook configuration resources during bootstrapping.")
|
||||
webhookCmd.PersistentFlags().BoolVar(&enableValidations, "validate", true, "Enable the validating webhook to reject workloads with issues")
|
||||
webhookCmd.PersistentFlags().BoolVar(&enableMutations, "mutate", false, "Enable the mutating webhook to modify workloads with issues")
|
||||
webhookCmd.PersistentFlags().StringVar(&certDir, "cert-dir", "/opt/cert", "Directory in which tls certificate is located")
|
||||
}
|
||||
|
||||
var webhookCmd = &cobra.Command{
|
||||
Use: "webhook",
|
||||
Short: "Runs the webhook webserver.",
|
||||
Long: `Runs the webhook webserver.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
logrus.Debug("Setting up controller manager")
|
||||
|
||||
mgr, err := manager.New(k8sConfig.GetConfigOrDie(), manager.Options{
|
||||
CertDir: certDir,
|
||||
Port: webhookPort,
|
||||
})
|
||||
if err != nil {
|
||||
logrus.Errorf("Unable to set up overall controller manager: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
_, err = os.Stat(certDir + "/tls.crt")
|
||||
if os.IsNotExist(err) {
|
||||
panic("Cert does not exist")
|
||||
}
|
||||
server := mgr.GetWebhookServer()
|
||||
server.CertName = "tls.crt"
|
||||
server.KeyName = "tls.key"
|
||||
|
||||
if !enableMutations && !enableValidations {
|
||||
logrus.Errorf("One of --mutate or --validate must be set to true")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if enableValidations {
|
||||
fwebhook.NewValidateWebhook(mgr, fwebhook.Validator{Config: config, Client: mgr.GetClient()})
|
||||
}
|
||||
if enableMutations {
|
||||
fwebhook.NewMutateWebhook(mgr, fwebhook.Mutator{Config: config, Client: mgr.GetClient()})
|
||||
}
|
||||
logrus.Infof("Polaris webhook server listening on port %d", webhookPort)
|
||||
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
|
||||
logrus.Errorf("Error starting manager: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
coverage:
|
||||
range: 50...80
|
||||
|
Before Width: | Height: | Size: 267 KiB |
@@ -1,212 +0,0 @@
|
||||
---
|
||||
# Source: polaris/templates/0-namespace.yaml
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: polaris
|
||||
---
|
||||
# Source: polaris/templates/configmap.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: polaris
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
data:
|
||||
config.yaml: |
|
||||
resources:
|
||||
cpuRequestsMissing: warning
|
||||
cpuLimitsMissing: warning
|
||||
memoryRequestsMissing: warning
|
||||
memoryLimitsMissing: warning
|
||||
images:
|
||||
tagNotSpecified: error
|
||||
healthChecks:
|
||||
readinessProbeMissing: warning
|
||||
livenessProbeMissing: warning
|
||||
networking:
|
||||
hostNetworkSet: warning
|
||||
hostPortSet: warning
|
||||
security:
|
||||
hostIPCSet: error
|
||||
hostPIDSet: error
|
||||
notReadOnlyRootFileSystem: warning
|
||||
privilegeEscalationAllowed: error
|
||||
runAsRootAllowed: warning
|
||||
runAsPrivileged: error
|
||||
capabilities:
|
||||
error:
|
||||
ifAnyAdded:
|
||||
- SYS_ADMIN
|
||||
- NET_ADMIN
|
||||
- ALL
|
||||
warning:
|
||||
ifAnyAddedBeyond:
|
||||
- CHOWN
|
||||
- DAC_OVERRIDE
|
||||
- FSETID
|
||||
- FOWNER
|
||||
- MKNOD
|
||||
- NET_RAW
|
||||
- SETGID
|
||||
- SETUID
|
||||
- SETFCAP
|
||||
- SETPCAP
|
||||
- NET_BIND_SERVICE
|
||||
- SYS_CHROOT
|
||||
- KILL
|
||||
- AUDIT_WRITE
|
||||
|
||||
---
|
||||
# Source: polaris/templates/dashboard.rbac.yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: polaris-dashboard
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: polaris-dashboard
|
||||
labels:
|
||||
app: polaris
|
||||
rules:
|
||||
- apiGroups:
|
||||
- 'apps'
|
||||
- 'extensions'
|
||||
resources:
|
||||
- 'deployments'
|
||||
verbs:
|
||||
- 'get'
|
||||
- 'list'
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- 'nodes'
|
||||
- 'namespaces'
|
||||
- 'pods'
|
||||
verbs:
|
||||
- 'get'
|
||||
- 'list'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: polaris-dashboard
|
||||
labels:
|
||||
app: polaris
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: polaris-dashboard
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: polaris-dashboard
|
||||
namespace: polaris
|
||||
---
|
||||
# Source: polaris/templates/dashboard.service.yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: polaris-dashboard
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
spec:
|
||||
ports:
|
||||
- name: dashboard
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: polaris
|
||||
component: dashboard
|
||||
type: ClusterIP
|
||||
---
|
||||
# Source: polaris/templates/dashboard.deployment.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: '6ec4a4dc87403cae67c01438398a5f1d4ef836ffeaf26a33b685c066b940495a'
|
||||
name: polaris-dashboard
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
component: dashboard
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: polaris
|
||||
component: dashboard
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: polaris
|
||||
component: dashboard
|
||||
spec:
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: polaris
|
||||
containers:
|
||||
- command:
|
||||
- polaris
|
||||
- --dashboard
|
||||
- --config
|
||||
- /opt/app/config.yaml
|
||||
image: 'quay.io/reactiveops/polaris:0.1.5'
|
||||
imagePullPolicy: 'Always'
|
||||
name: dashboard
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 20
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 20
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
privileged: false
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /opt/app/config.yaml
|
||||
subPath: config.yaml
|
||||
readOnly: true
|
||||
serviceAccountName: polaris-dashboard
|
||||
---
|
||||
# Source: polaris/templates/webhook.deployment.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/webhook.rbac.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/webhook.secret.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/webhook.service.yaml
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
apiVersion: v1
|
||||
description: Validation of best practices in your Kubernetes clusters
|
||||
name: polaris
|
||||
version: 0.1.5
|
||||
@@ -1,6 +0,0 @@
|
||||
{{- if .Values.templateOnly -}}
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: {{ .Release.Namespace }}
|
||||
{{- end -}}
|
||||
@@ -1,12 +0,0 @@
|
||||
** Please be patient while the chart is being deployed **
|
||||
|
||||
Enjoy Polaris and smooth sailing!
|
||||
|
||||
{{- if contains "ClusterIP" .Values.dashboard.service.type }}
|
||||
|
||||
## To view the dashboard execute these commands:
|
||||
|
||||
kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ include "polaris.fullname" . }}-dashboard 8080:80 &
|
||||
open http://localhost:8080
|
||||
|
||||
{{- end }}
|
||||
@@ -1,56 +0,0 @@
|
||||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "polaris.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "polaris.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "polaris.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Standard labels
|
||||
*/}}
|
||||
{{- define "polaris.labels" -}}
|
||||
app: {{ include "polaris.name" . }}
|
||||
{{- if not .Values.templateOnly }}
|
||||
app.kubernetes.io/name: {{ include "polaris.name" . }}
|
||||
helm.sh/chart: {{ include "polaris.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Standard selector
|
||||
*/}}
|
||||
{{- define "polaris.selectors" -}}
|
||||
app: {{ include "polaris.name" . }}
|
||||
{{- if not .Values.templateOnly }}
|
||||
app.kubernetes.io/name: {{ include "polaris.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
@@ -1,9 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "polaris.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
data:
|
||||
config.yaml: {{- toYaml .Values.config | indent 2 -}}
|
||||
@@ -1,72 +0,0 @@
|
||||
{{- if .Values.dashboard.enable -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: '{{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}'
|
||||
name: {{ include "polaris.fullname" . }}-dashboard
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
component: dashboard
|
||||
spec:
|
||||
replicas: {{.Values.dashboard.replicas}}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "polaris.selectors" . | nindent 6 }}
|
||||
component: dashboard
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "polaris.selectors" . | nindent 8 }}
|
||||
component: dashboard
|
||||
spec:
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: {{ include "polaris.fullname" . }}
|
||||
containers:
|
||||
- command:
|
||||
- polaris
|
||||
- --dashboard
|
||||
- --config
|
||||
- /opt/app/config.yaml
|
||||
image: '{{.Values.dashboard.image.repository}}:{{.Values.dashboard.image.tag}}'
|
||||
imagePullPolicy: '{{.Values.dashboard.image.pullPolicy}}'
|
||||
name: dashboard
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 20
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 20
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
privileged: false
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /opt/app/config.yaml
|
||||
subPath: config.yaml
|
||||
readOnly: true
|
||||
serviceAccountName: {{ include "polaris.fullname" . }}-dashboard
|
||||
{{- end -}}
|
||||
@@ -1,49 +0,0 @@
|
||||
{{- if and .Values.dashboard.enable .Values.rbac.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "polaris.fullname" . }}-dashboard
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "polaris.fullname" . }}-dashboard
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- 'apps'
|
||||
- 'extensions'
|
||||
resources:
|
||||
- 'deployments'
|
||||
verbs:
|
||||
- 'get'
|
||||
- 'list'
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- 'nodes'
|
||||
- 'namespaces'
|
||||
- 'pods'
|
||||
verbs:
|
||||
- 'get'
|
||||
- 'list'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "polaris.fullname" . }}-dashboard
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ include "polaris.fullname" . }}-dashboard
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "polaris.fullname" . }}-dashboard
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end -}}
|
||||
@@ -1,19 +0,0 @@
|
||||
{{- if and .Values.dashboard.enable .Values.dashboard.service -}}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "polaris.fullname" . }}-dashboard
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
spec:
|
||||
ports:
|
||||
- name: dashboard
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
{{- include "polaris.selectors" . | nindent 4 }}
|
||||
component: dashboard
|
||||
type: {{ .Values.dashboard.service.type }}
|
||||
{{- end -}}
|
||||
@@ -1,90 +0,0 @@
|
||||
{{- if .Values.webhook.enable -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: '{{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}'
|
||||
name: {{ include "polaris.fullname" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
component: webhook
|
||||
spec:
|
||||
replicas: {{ .Values.webhook.replicas }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "polaris.selectors" . | nindent 6 }}
|
||||
component: webhook
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "polaris.selectors" . | nindent 8 }}
|
||||
component: webhook
|
||||
spec:
|
||||
containers:
|
||||
- name: webhook
|
||||
command:
|
||||
- polaris
|
||||
- --webhook
|
||||
- --config
|
||||
- /opt/app/config.yaml
|
||||
image: '{{.Values.webhook.image.repository}}:{{.Values.webhook.image.tag}}'
|
||||
imagePullPolicy: '{{.Values.webhook.image.pullPolicy}}'
|
||||
ports:
|
||||
- containerPort: 9876
|
||||
# These are fairly useless readiness/liveness probes for now
|
||||
# Follow this issue for potential improvements:
|
||||
# https://github.com/kubernetes-sigs/controller-runtime/issues/356
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- ps -ef | grep polaris
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- ps -ef | grep polaris
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
privileged: false
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /opt/app/config.yaml
|
||||
subPath: config.yaml
|
||||
readOnly: true
|
||||
- name: secret
|
||||
mountPath: /opt/cert/
|
||||
readOnly: true
|
||||
- name: cr-logs
|
||||
mountPath: /tmp/
|
||||
readOnly: false
|
||||
serviceAccountName: {{ include "polaris.fullname" . }}-webhook
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: {{ include "polaris.fullname" . }}
|
||||
- name: secret
|
||||
secret:
|
||||
secretName: polaris-webhook
|
||||
- name: cr-logs
|
||||
emptyDir: {}
|
||||
{{- end -}}
|
||||
@@ -1,90 +0,0 @@
|
||||
{{- if and .Values.webhook.enable .Values.rbac.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "polaris.fullname" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "polaris.fullname" . }}-webhook
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- 'apps'
|
||||
- 'extensions'
|
||||
resources:
|
||||
- 'deployments'
|
||||
verbs:
|
||||
- 'get'
|
||||
- 'list'
|
||||
# required by controller-runtime code doing a cluster wide lookup
|
||||
# when it seems namespace would suffice
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- 'secrets'
|
||||
- 'services'
|
||||
verbs:
|
||||
- 'get'
|
||||
- 'list'
|
||||
- 'watch'
|
||||
- apiGroups:
|
||||
- 'admissionregistration.k8s.io'
|
||||
resources:
|
||||
- 'validatingwebhookconfigurations'
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "polaris.fullname" . }}-webhook
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ include "polaris.fullname" . }}-webhook
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "polaris.fullname" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ include "polaris.fullname" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
rules:
|
||||
# required for current controller-runtime bootstrap method
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- 'secrets'
|
||||
- 'services'
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ include "polaris.fullname" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: {{ include "polaris.fullname" . }}-webhook
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "polaris.fullname" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end -}}
|
||||
@@ -1,12 +0,0 @@
|
||||
{{- if .Values.webhook.enable -}}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: polaris-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
cert.pem: ''
|
||||
{{- end -}}
|
||||
@@ -1,19 +0,0 @@
|
||||
{{- if .Values.webhook.enable -}}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: polaris-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "polaris.labels" . | nindent 4 }}
|
||||
spec:
|
||||
ports:
|
||||
- name: webhook
|
||||
port: 443
|
||||
protocol: TCP
|
||||
targetPort: 9876
|
||||
selector:
|
||||
{{- include "polaris.selectors" . | nindent 4 }}
|
||||
component: webhook
|
||||
type: ClusterIP
|
||||
{{- end -}}
|
||||
@@ -1,67 +0,0 @@
|
||||
---
|
||||
config: |
|
||||
resources:
|
||||
cpuRequestsMissing: warning
|
||||
cpuLimitsMissing: warning
|
||||
memoryRequestsMissing: warning
|
||||
memoryLimitsMissing: warning
|
||||
images:
|
||||
tagNotSpecified: error
|
||||
healthChecks:
|
||||
readinessProbeMissing: warning
|
||||
livenessProbeMissing: warning
|
||||
networking:
|
||||
hostNetworkSet: warning
|
||||
hostPortSet: warning
|
||||
security:
|
||||
hostIPCSet: error
|
||||
hostPIDSet: error
|
||||
notReadOnlyRootFileSystem: warning
|
||||
privilegeEscalationAllowed: error
|
||||
runAsRootAllowed: warning
|
||||
runAsPrivileged: error
|
||||
capabilities:
|
||||
error:
|
||||
ifAnyAdded:
|
||||
- SYS_ADMIN
|
||||
- NET_ADMIN
|
||||
- ALL
|
||||
warning:
|
||||
ifAnyAddedBeyond:
|
||||
- CHOWN
|
||||
- DAC_OVERRIDE
|
||||
- FSETID
|
||||
- FOWNER
|
||||
- MKNOD
|
||||
- NET_RAW
|
||||
- SETGID
|
||||
- SETUID
|
||||
- SETFCAP
|
||||
- SETPCAP
|
||||
- NET_BIND_SERVICE
|
||||
- SYS_CHROOT
|
||||
- KILL
|
||||
- AUDIT_WRITE
|
||||
|
||||
dashboard:
|
||||
enable: true
|
||||
replicas: 1
|
||||
service:
|
||||
type: ClusterIP
|
||||
image:
|
||||
repository: quay.io/reactiveops/polaris
|
||||
tag: 0.1.5
|
||||
pullPolicy: Always
|
||||
|
||||
webhook:
|
||||
enable: false
|
||||
replicas: 1
|
||||
image:
|
||||
repository: quay.io/reactiveops/polaris
|
||||
tag: 0.1.5
|
||||
pullPolicy: Always
|
||||
|
||||
rbac:
|
||||
create: true
|
||||
|
||||
templateOnly: false
|
||||
@@ -1,280 +0,0 @@
|
||||
---
|
||||
# Source: polaris/templates/0-namespace.yaml
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: polaris
|
||||
---
|
||||
# Source: polaris/templates/webhook.secret.yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: polaris-webhook
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
type: Opaque
|
||||
stringData:
|
||||
cert.pem: ''
|
||||
---
|
||||
# Source: polaris/templates/configmap.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: polaris
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
data:
|
||||
config.yaml: |
|
||||
resources:
|
||||
cpuRequestsMissing: warning
|
||||
cpuLimitsMissing: warning
|
||||
memoryRequestsMissing: warning
|
||||
memoryLimitsMissing: warning
|
||||
images:
|
||||
tagNotSpecified: error
|
||||
healthChecks:
|
||||
readinessProbeMissing: warning
|
||||
livenessProbeMissing: warning
|
||||
networking:
|
||||
hostNetworkSet: warning
|
||||
hostPortSet: warning
|
||||
security:
|
||||
hostIPCSet: error
|
||||
hostPIDSet: error
|
||||
notReadOnlyRootFileSystem: warning
|
||||
privilegeEscalationAllowed: error
|
||||
runAsRootAllowed: warning
|
||||
runAsPrivileged: error
|
||||
capabilities:
|
||||
error:
|
||||
ifAnyAdded:
|
||||
- SYS_ADMIN
|
||||
- NET_ADMIN
|
||||
- ALL
|
||||
warning:
|
||||
ifAnyAddedBeyond:
|
||||
- CHOWN
|
||||
- DAC_OVERRIDE
|
||||
- FSETID
|
||||
- FOWNER
|
||||
- MKNOD
|
||||
- NET_RAW
|
||||
- SETGID
|
||||
- SETUID
|
||||
- SETFCAP
|
||||
- SETPCAP
|
||||
- NET_BIND_SERVICE
|
||||
- SYS_CHROOT
|
||||
- KILL
|
||||
- AUDIT_WRITE
|
||||
|
||||
---
|
||||
# Source: polaris/templates/webhook.rbac.yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: polaris-webhook
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: polaris-webhook
|
||||
labels:
|
||||
app: polaris
|
||||
rules:
|
||||
- apiGroups:
|
||||
- 'apps'
|
||||
- 'extensions'
|
||||
resources:
|
||||
- 'deployments'
|
||||
verbs:
|
||||
- 'get'
|
||||
- 'list'
|
||||
# required by controller-runtime code doing a cluster wide lookup
|
||||
# when it seems namespace would suffice
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- 'secrets'
|
||||
- 'services'
|
||||
verbs:
|
||||
- 'get'
|
||||
- 'list'
|
||||
- 'watch'
|
||||
- apiGroups:
|
||||
- 'admissionregistration.k8s.io'
|
||||
resources:
|
||||
- 'validatingwebhookconfigurations'
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: polaris-webhook
|
||||
labels:
|
||||
app: polaris
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: polaris-webhook
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: polaris-webhook
|
||||
namespace: polaris
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: polaris-webhook
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
rules:
|
||||
# required for current controller-runtime bootstrap method
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- 'secrets'
|
||||
- 'services'
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: polaris-webhook
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: polaris-webhook
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: polaris-webhook
|
||||
namespace: polaris
|
||||
---
|
||||
# Source: polaris/templates/webhook.service.yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: polaris-webhook
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
spec:
|
||||
ports:
|
||||
- name: webhook
|
||||
port: 443
|
||||
protocol: TCP
|
||||
targetPort: 9876
|
||||
selector:
|
||||
app: polaris
|
||||
component: webhook
|
||||
type: ClusterIP
|
||||
---
|
||||
# Source: polaris/templates/webhook.deployment.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: '6ec4a4dc87403cae67c01438398a5f1d4ef836ffeaf26a33b685c066b940495a'
|
||||
name: polaris-webhook
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
component: webhook
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: polaris
|
||||
component: webhook
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: polaris
|
||||
component: webhook
|
||||
spec:
|
||||
containers:
|
||||
- name: webhook
|
||||
command:
|
||||
- polaris
|
||||
- --webhook
|
||||
- --config
|
||||
- /opt/app/config.yaml
|
||||
image: 'quay.io/reactiveops/polaris:0.1.5'
|
||||
imagePullPolicy: 'Always'
|
||||
ports:
|
||||
- containerPort: 9876
|
||||
# These are fairly useless readiness/liveness probes for now
|
||||
# Follow this issue for potential improvements:
|
||||
# https://github.com/kubernetes-sigs/controller-runtime/issues/356
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- ps -ef | grep polaris
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- ps -ef | grep polaris
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
privileged: false
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /opt/app/config.yaml
|
||||
subPath: config.yaml
|
||||
readOnly: true
|
||||
- name: secret
|
||||
mountPath: /opt/cert/
|
||||
readOnly: true
|
||||
- name: cr-logs
|
||||
mountPath: /tmp/
|
||||
readOnly: false
|
||||
serviceAccountName: polaris-webhook
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: polaris
|
||||
- name: secret
|
||||
secret:
|
||||
secretName: polaris-webhook
|
||||
- name: cr-logs
|
||||
emptyDir: {}
|
||||
---
|
||||
# Source: polaris/templates/dashboard.deployment.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/dashboard.rbac.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/dashboard.service.yaml
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
module.exports = {
|
||||
title: "Fairwinds Polaris Documentation",
|
||||
description: "Documentation for Fairwinds Polaris - audit and enforce Kubernetes best practices for your workloads",
|
||||
themeConfig: {
|
||||
docsRepo: "FairwindsOps/polaris",
|
||||
sidebar: [
|
||||
{
|
||||
title: "Polaris",
|
||||
path: "/",
|
||||
sidebarDepth: 0,
|
||||
collapsable: false,
|
||||
children: [
|
||||
{
|
||||
title: "Changelog",
|
||||
path: "/changelog",
|
||||
},
|
||||
{
|
||||
title: "Code of Conduct",
|
||||
path: "/code-of-conduct",
|
||||
},
|
||||
{
|
||||
title: "Contributing",
|
||||
path: "/contributing",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Ways to Run Polaris",
|
||||
collapsable: false,
|
||||
children: [
|
||||
"/dashboard",
|
||||
"/admission-controller",
|
||||
"/infrastructure-as-code",
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Usage",
|
||||
collapsable: false,
|
||||
children: [
|
||||
"/cli",
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Customization",
|
||||
collapsable: false,
|
||||
children: [
|
||||
"/customization/configuration",
|
||||
"/customization/checks",
|
||||
"/customization/custom-checks",
|
||||
"/customization/exemptions",
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Checks",
|
||||
collapsable: false,
|
||||
sidebarDepth: 0,
|
||||
children: [
|
||||
"/checks/security",
|
||||
"/checks/efficiency",
|
||||
"/checks/reliability",
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// This file is generated from FairwindsOps/documentation-template
|
||||
// DO NOT EDIT MANUALLY
|
||||
|
||||
const fs = require('fs');
|
||||
const npath = require('path');
|
||||
|
||||
const CONFIG_FILE = npath.join(__dirname, 'config-extras.js');
|
||||
const BASE_DIR = npath.join(__dirname, '..');
|
||||
|
||||
const extras = require(CONFIG_FILE);
|
||||
if (!extras.title || !extras.description || !extras.themeConfig.docsRepo) {
|
||||
throw new Error("Please specify 'title', 'description', and 'themeConfig.docsRepo' in config-extras.js");
|
||||
}
|
||||
|
||||
const docFiles = fs.readdirSync(BASE_DIR)
|
||||
.filter(f => f !== "README.md")
|
||||
.filter(f => f !== ".vuepress")
|
||||
.filter(f => f !== "node_modules")
|
||||
.filter(f => npath.extname(f) === '.md' || npath.extname(f) === '');
|
||||
|
||||
const sidebar = [['/', 'Home']].concat(docFiles.map(f => {
|
||||
const ext = npath.extname(f);
|
||||
if (ext === '') {
|
||||
// this is a directory
|
||||
const title = f;
|
||||
const children = fs.readdirSync(npath.join(BASE_DIR, f)).map(subf => {
|
||||
return '/' + f + '/' + npath.basename(subf);
|
||||
});
|
||||
return {title, children};
|
||||
}
|
||||
const path = npath.basename(f);
|
||||
return path;
|
||||
}));
|
||||
|
||||
const baseConfig = {
|
||||
title: "",
|
||||
description: "",
|
||||
head: [
|
||||
['link', { rel: 'icon', href: '/favicon.png' }],
|
||||
['script', { src: '/scripts/modify.js' }],
|
||||
['script', { src: '/scripts/marketing.js' }],
|
||||
],
|
||||
themeConfig: {
|
||||
docsRepo: "",
|
||||
docsDir: 'docs',
|
||||
editLinks: true,
|
||||
editLinkText: "Help us improve this page",
|
||||
logo: '/img/fairwinds-logo.svg',
|
||||
heroText: "",
|
||||
sidebar,
|
||||
nav: [
|
||||
{text: 'View on GitHub', link: 'https://github.com/' + extras.themeConfig.docsRepo},
|
||||
],
|
||||
},
|
||||
plugins: {
|
||||
'vuepress-plugin-clean-urls': {
|
||||
normalSuffix: '/',
|
||||
notFoundPath: '/404.html',
|
||||
},
|
||||
'check-md': {},
|
||||
},
|
||||
}
|
||||
|
||||
let config = JSON.parse(JSON.stringify(baseConfig))
|
||||
if (!fs.existsSync(CONFIG_FILE)) {
|
||||
throw new Error("Please add config-extras.js to specify your project details");
|
||||
}
|
||||
for (let key in extras) {
|
||||
if (!config[key]) config[key] = extras[key];
|
||||
else if (key === 'head') config[key] = config[key].concat(extras[key]);
|
||||
else Object.assign(config[key], extras[key]);
|
||||
}
|
||||
module.exports = config;
|
||||
|
After Width: | Height: | Size: 400 B |
@@ -0,0 +1,421 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 3000 706.2" style="enable-background:new 0 0 3000 706.2;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#231039;}
|
||||
.st1{fill:#6D6D6D;}
|
||||
.st2{font-family:'CircularStd-Book';}
|
||||
.st3{font-size:88.0749px;}
|
||||
.st4{fill:#F36D21;}
|
||||
.st5{fill:none;stroke:#F36D21;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
|
||||
.st6{fill:#898989;}
|
||||
.st7{fill:#BCBCBC;}
|
||||
.st8{fill:none;}
|
||||
.st9{fill:#DBDBDB;}
|
||||
.st10{enable-background:new ;}
|
||||
.st11{fill:#23183A;}
|
||||
.st12{fill:#B5B5B5;}
|
||||
.st13{fill:#9F234F;}
|
||||
.st14{fill:#F08117;}
|
||||
.st15{fill:#8ED0D9;}
|
||||
.st16{fill:#A3A3A3;}
|
||||
.st17{fill:#D1D1D1;}
|
||||
.st18{fill:#D1D1D1;stroke:#23183A;stroke-width:2.3711;stroke-miterlimit:10;}
|
||||
.st19{fill:none;stroke:#D1D1D1;stroke-width:6.6619;stroke-miterlimit:10;}
|
||||
.st20{fill:#23103A;}
|
||||
.st21{fill:#270D3C;}
|
||||
.st22{fill:#26163C;}
|
||||
.st23{fill:#F26722;}
|
||||
.st24{fill:#F78F1E;}
|
||||
.st25{fill:#F9AC78;}
|
||||
.st26{fill:#FF6700;}
|
||||
.st27{fill:url(#SVGID_1_);}
|
||||
.st28{fill:url(#SVGID_2_);}
|
||||
.st29{fill:url(#SVGID_3_);}
|
||||
.st30{fill:url(#SVGID_4_);}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M317.7,177.6h-149v-49.3h174.4v23.9C343.1,166.3,331.7,177.6,317.7,177.6z"/>
|
||||
<path class="st0" d="M254.3,247.2h-85.6v-49.3h111v23.9C279.7,235.9,268.3,247.2,254.3,247.2z"/>
|
||||
<path class="st0" d="M192.7,316.8h-24v-49.3H218v23.9C218,305.5,206.7,316.8,192.7,316.8z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M398.5,287.3V136.7h93.7v24H424V203h61.2v23.6H424v60.8H398.5z"/>
|
||||
<path class="st0" d="M532.1,228l26.6-4c6-0.8,7.6-3.8,7.6-7.4c0-8.7-5.9-15.7-19.5-15.7c-13,0-20.2,8.3-21.2,18.7l-22.5-5.1
|
||||
c1.9-17.8,18.1-33.8,43.6-33.8c31.9,0,44,18.1,44,38.7v51.4c0,9.3,1.1,15.5,1.3,16.6h-22.9c-0.2-0.6-1.1-4.9-1.1-13.2
|
||||
c-4.9,7.9-15.1,16.4-31.9,16.4c-21.7,0-35.1-14.9-35.1-31.2C500.9,240.8,514.5,230.6,532.1,228z M566.3,244.4v-4.7l-27,4
|
||||
c-7.6,1.3-13.8,5.5-13.8,14c0,7,5.3,13.4,15.1,13.4C554.4,271.2,566.3,264.6,566.3,244.4z"/>
|
||||
<path class="st0" d="M632.4,131.4c8.9,0,16.1,7.2,16.1,16.1s-7.2,15.9-16.1,15.9c-8.7,0-15.9-7-15.9-15.9S623.7,131.4,632.4,131.4
|
||||
z M620.3,287.3V183.9h24.4v103.5H620.3z"/>
|
||||
<path class="st0" d="M737.2,208.3c-2.8-0.4-5.5-0.6-8.1-0.6c-19.1,0-27.8,11-27.8,30.4v49.3h-24.6V183.9h24v16.6
|
||||
c4.9-11.3,16.4-17.8,30-17.8c3,0,5.5,0.4,6.6,0.6V208.3z"/>
|
||||
<path class="st0" d="M844.3,183.9l24.4,71.6l20.6-71.6h25.1l-33.1,103.5h-24.6L830.9,213l-25.1,74.4h-25.3L747,183.9h26.3l21,71.6
|
||||
l24.4-71.6H844.3z"/>
|
||||
<path class="st0" d="M945.2,131.4c8.9,0,16.1,7.2,16.1,16.1s-7.2,15.9-16.1,15.9c-8.7,0-15.9-7-15.9-15.9S936.5,131.4,945.2,131.4
|
||||
z M933.1,287.3V183.9h24.4v103.5H933.1z"/>
|
||||
<path class="st0" d="M1014.1,287.3h-24.6V183.9h24v13.8c6.8-11.9,19.1-16.8,30.6-16.8c25.3,0,37.4,18.3,37.4,41v65.4h-24.6v-61.2
|
||||
c0-12.8-5.7-22.9-21.2-22.9c-14,0-21.5,10.8-21.5,24.4V287.3z"/>
|
||||
<path class="st0" d="M1207,268.4c0,9.3,0.9,17.2,1.1,18.9h-23.6c-0.4-2.3-1.1-9.1-1.1-13.4c-4.9,8.7-15.7,15.9-30.4,15.9
|
||||
c-29.7,0-49.7-23.4-49.7-54.6c0-29.8,20.2-54.2,49.3-54.2c18.1,0,27.2,8.3,30.4,14.9v-62.5h24V268.4z M1155.8,268.2
|
||||
c16.1,0,27.4-13.4,27.4-33.1s-11-32.1-27.2-32.1c-16.1,0-28,12.5-28,32.3C1128,255,1139,268.2,1155.8,268.2z"/>
|
||||
<path class="st0" d="M1251.6,253.3c0.9,9.3,7.9,17.6,21,17.6c10.2,0,15.5-5.5,15.5-11.9c0-5.5-3.8-9.8-12.1-11.5l-15.3-3.4
|
||||
c-18.3-4-27.8-15.9-27.8-30.2c0-18.1,16.6-33.4,38-33.4c28.9,0,38.2,18.7,39.9,28.9l-20.8,5.9c-0.9-5.9-5.3-15.5-19.1-15.5
|
||||
c-8.7,0-14.9,5.5-14.9,11.9c0,5.5,4,9.6,10.4,10.8l15.7,3.2c19.5,4.2,29.7,16.2,29.7,31.4c0,15.7-12.7,33.1-39.1,33.1
|
||||
c-30,0-41.4-19.5-42.7-31.2L1251.6,253.3z"/>
|
||||
<path class="st0" d="M1391.2,287.3V136.7h25.9v150.7H1391.2z"/>
|
||||
<path class="st0" d="M1475.8,287.3h-24.6V183.9h24v13.8c6.8-11.9,19.1-16.8,30.6-16.8c25.3,0,37.4,18.3,37.4,41v65.4h-24.6v-61.2
|
||||
c0-12.8-5.7-22.9-21.2-22.9c-14,0-21.5,10.8-21.5,24.4V287.3z"/>
|
||||
<path class="st0" d="M1585.4,253.3c0.9,9.3,7.9,17.6,21,17.6c10.2,0,15.5-5.5,15.5-11.9c0-5.5-3.8-9.8-12.1-11.5l-15.3-3.4
|
||||
c-18.3-4-27.8-15.9-27.8-30.2c0-18.1,16.6-33.4,38-33.4c28.9,0,38.2,18.7,39.9,28.9l-20.8,5.9c-0.9-5.9-5.3-15.5-19.1-15.5
|
||||
c-8.7,0-14.9,5.5-14.9,11.9c0,5.5,4,9.6,10.4,10.8l15.7,3.2c19.5,4.2,29.7,16.2,29.7,31.4c0,15.7-12.7,33.1-39.1,33.1
|
||||
c-30,0-41.4-19.5-42.7-31.2L1585.4,253.3z"/>
|
||||
<path class="st0" d="M1682.3,131.4c8.9,0,16.1,7.2,16.1,16.1s-7.2,15.9-16.1,15.9c-8.7,0-15.9-7-15.9-15.9
|
||||
S1673.6,131.4,1682.3,131.4z M1670.2,287.3V183.9h24.4v103.5H1670.2z"/>
|
||||
<path class="st0" d="M1741.8,287.1c1.7,12.8,11.7,22.3,25.9,22.3c19.5,0,29.3-10,29.3-31v-10.8c-4.5,8.1-14.9,15.1-30,15.1
|
||||
c-27.6,0-47.8-21.2-47.8-50.4c0-27.6,19.3-50.4,47.8-50.4c16.1,0,26.1,6.6,30.6,15.1v-13.2h23.8v93.7c0,27.6-14.2,53.3-53.1,53.3
|
||||
c-27.4,0-46.5-17-49.3-37.8L1741.8,287.1z M1797.7,232.3c0-17.6-11.3-29.1-26.6-29.1c-15.7,0-27,11.5-27,29.1
|
||||
c0,18.1,10.8,29.3,27,29.3C1786.9,261.6,1797.7,250.1,1797.7,232.3z"/>
|
||||
<path class="st0" d="M1876.3,287.3h-24.6V133.5h24.6v60.3c7-9.1,18.7-13,29.5-13c25.5,0,37.8,18.3,37.8,41v65.4H1919v-61.2
|
||||
c0-12.8-5.7-22.9-21.2-22.9c-13.6,0-21,10.2-21.5,23.4V287.3z"/>
|
||||
<path class="st0" d="M2004.9,183.9h21.5v21.9h-21.5v48c0,9.1,4,13,13.2,13c3.4,0,7.4-0.6,8.5-0.8v20.4c-1.5,0.6-6.2,2.3-15.1,2.3
|
||||
c-19.1,0-31-11.5-31-30.8v-52.1h-19.1v-21.9h5.3c11,0,15.9-7,15.9-16.1v-15.5h22.3V183.9z"/>
|
||||
<path class="st0" d="M2065.7,253.3c0.9,9.3,7.9,17.6,21,17.6c10.2,0,15.5-5.5,15.5-11.9c0-5.5-3.8-9.8-12.1-11.5l-15.3-3.4
|
||||
c-18.3-4-27.8-15.9-27.8-30.2c0-18.1,16.6-33.4,38-33.4c28.9,0,38.2,18.7,39.9,28.9l-20.8,5.9c-0.9-5.9-5.3-15.5-19.1-15.5
|
||||
c-8.7,0-14.9,5.5-14.9,11.9c0,5.5,4,9.6,10.4,10.8l15.7,3.2c19.5,4.2,29.7,16.2,29.7,31.4c0,15.7-12.7,33.1-39.1,33.1
|
||||
c-30,0-41.4-19.5-42.7-31.2L2065.7,253.3z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<text transform="matrix(1 0 0 1 2512.0906 491.5612)" class="st1 st2 st3">more</text>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<text transform="matrix(1 0 0 1 2088.605 491.561)" class="st4 st2 st3">+</text>
|
||||
</g>
|
||||
<g>
|
||||
<text transform="matrix(1 0 0 1 2439.4316 491.561)" class="st4 st2 st3">+</text>
|
||||
</g>
|
||||
<g>
|
||||
<text transform="matrix(1 0 0 1 1567.2388 491.561)" class="st4 st2 st3">+</text>
|
||||
</g>
|
||||
<g>
|
||||
<text transform="matrix(1 0 0 1 1250.0308 491.5612)" class="st4 st2 st3">+</text>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st5" d="M524.4,621.6c0,0,476.7-73.4,685.5-33.6"/>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st1" d="M1453,505.9c-0.8-0.1-1.6,0.3-2,1V503h-1.2v9.2h1.2v-0.9c0.4,0.7,1.2,1.1,2,1c1.8,0,2.8-1.4,2.8-3.2
|
||||
C1455.8,507.2,1454.9,505.9,1453,505.9z M1452.8,511.3c-1,0-1.8-0.8-1.8-2.2c-0.1-1,0.6-2,1.6-2.1c0.1,0,0.1,0,0.2,0
|
||||
c1.1,0,1.8,0.8,1.8,2.1C1454.6,510.4,1453.9,511.3,1452.8,511.3z"/>
|
||||
<polygon class="st1" points="1459.4,510.3 1457.5,506.1 1456.2,506.1 1458.8,511.5 1457.3,514.7 1458.6,514.7 1462.6,506.1
|
||||
1461.2,506.1 "/>
|
||||
<path class="st1" d="M1466.4,512.6h1.1c0.5,0,0.9-0.4,0.9-0.9l0,0v-3.2h1.5c0.7,0,1.2-0.6,1.2-1.3v-0.6h-2.8v-2.2h3
|
||||
c0.6,0,1.1-0.5,1.1-1.1v-0.7h-6.2L1466.4,512.6z"/>
|
||||
<path class="st1" d="M1476.2,505.1c-0.7,0-1.4,0.2-2,0.7c-0.5,0.5-0.8,1.1-0.9,1.8h1.8c0-0.2,0.1-0.5,0.3-0.6
|
||||
c0.2-0.2,0.5-0.3,0.8-0.2c0.3,0,0.6,0.1,0.8,0.2c0.2,0.2,0.3,0.5,0.2,0.8v0.2l-1.9,0.3c-0.3,0-0.6,0.1-0.9,0.2
|
||||
c-0.3,0.1-0.5,0.2-0.7,0.4c-0.2,0.1-0.4,0.3-0.5,0.6c-0.1,0.3-0.2,0.6-0.2,0.9c0,0.6,0.2,1.1,0.6,1.5c0.4,0.4,1,0.6,1.6,0.6
|
||||
c0.9,0.1,1.7-0.4,2.1-1.1v0.2c0.1,0.5,0.4,0.8,0.9,0.8h0.8v-4.7c0.1-0.7-0.2-1.5-0.8-2C1477.7,505.3,1476.9,505.1,1476.2,505.1z
|
||||
M1477.2,509.6c0,0.3-0.1,0.6-0.2,0.8c-0.1,0.2-0.3,0.4-0.5,0.5c-0.2,0.1-0.4,0.2-0.7,0.2c-0.2,0-0.4,0-0.6-0.2
|
||||
c-0.1-0.1-0.2-0.3-0.2-0.5s0-0.4,0.1-0.5c0.2-0.1,0.4-0.2,0.6-0.2l1.5-0.3V509.6L1477.2,509.6z"/>
|
||||
<path class="st1" d="M1481.7,502.1c-0.3,0-0.6,0.1-0.8,0.3s-0.4,0.5-0.4,0.8s0.1,0.6,0.3,0.8c0.2,0.2,0.5,0.3,0.8,0.3
|
||||
s0.6-0.1,0.8-0.3s0.4-0.5,0.4-0.8s-0.1-0.6-0.4-0.8C1482.3,502.2,1482,502.1,1481.7,502.1z"/>
|
||||
<path class="st1" d="M1480.8,512.6h0.9c0.5,0,0.9-0.4,0.9-0.9l0,0v-6.4h-1.9v7.3H1480.8z"/>
|
||||
<path class="st1" d="M1486.4,506.4l-0.2-1.1h-1.6v7.3h1c0.5,0,0.9-0.4,0.9-0.9l0,0v-2.8c0-0.5,0.2-1,0.6-1.3
|
||||
c0.4-0.3,0.9-0.5,1.4-0.5v-1.8c-0.5-0.1-1,0.1-1.4,0.3C1486.8,505.7,1486.6,506,1486.4,506.4z"/>
|
||||
<path class="st1" d="M1497.3,509.8l-0.1,0.8l-0.1-0.8l-1.2-4.3h-1.7l-1.2,4.3l-0.1,0.8l-0.1-0.8l-1.1-4.3h-2l2.2,7.3h1.2
|
||||
c0.4,0,0.8-0.3,0.9-0.7l1.1-3.6l1.1,4.2h1.3c0.4,0,0.8-0.3,0.9-0.7l2-6.6h-2L1497.3,509.8z"/>
|
||||
<path class="st1" d="M1502.4,502.1c-0.3,0-0.6,0.1-0.8,0.3c-0.2,0.2-0.4,0.5-0.4,0.8s0.1,0.6,0.4,0.8c0.2,0.2,0.5,0.3,0.8,0.3
|
||||
s0.6-0.1,0.8-0.3s0.4-0.5,0.4-0.8s-0.1-0.6-0.4-0.8C1503,502.2,1502.7,502.1,1502.4,502.1z"/>
|
||||
<path class="st1" d="M1501.5,512.6h0.9c0.5,0,0.9-0.4,0.9-0.9l0,0v-6.4h-1.9v7.3H1501.5z"/>
|
||||
<path class="st1" d="M1509.1,505.1c-0.4,0-0.8,0.1-1.2,0.3c-0.3,0.2-0.6,0.5-0.8,0.8l-0.1-1h-1.7v7.4h1c0.5,0,1-0.5,0.9-1v-2.8
|
||||
c0-0.5,0.1-0.9,0.4-1.3c0.2-0.3,0.5-0.5,0.9-0.4c0.3,0,0.6,0.1,0.8,0.3c0.2,0.3,0.3,0.6,0.2,1v4.2h0.9c0.6,0,1-0.4,1-1v-3.7
|
||||
c0-0.7-0.2-1.4-0.6-2C1510.4,505.3,1509.7,505.1,1509.1,505.1z"/>
|
||||
<path class="st1" d="M1518.3,506.1c-0.2-0.3-0.5-0.5-0.9-0.7c-0.4-0.2-0.9-0.2-1.3-0.2c-0.9,0-1.8,0.4-2.4,1.1
|
||||
c-0.7,0.7-1,1.7-1,2.7c0,0.7,0.1,1.3,0.4,1.9c0.3,0.6,0.7,1,1.3,1.4c0.5,0.3,1.1,0.5,1.7,0.5c0.9,0.1,1.8-0.4,2.3-1.1v0.2
|
||||
c0.1,0.4,0.5,0.7,1,0.7h0.8v-10.5h-1.9V506.1z M1518.3,509c0,0.5-0.2,1.1-0.6,1.5c-0.3,0.4-0.8,0.6-1.3,0.6s-1-0.2-1.3-0.6
|
||||
c-0.7-0.9-0.7-2.1,0-2.9c0.3-0.4,0.8-0.6,1.3-0.6c0.3,0,0.6,0.1,0.9,0.2c0.3,0.2,0.5,0.4,0.6,0.7c0.2,0.3,0.3,0.6,0.3,1v0.1
|
||||
H1518.3z"/>
|
||||
<path class="st1" d="M1526.8,509c-0.5-0.4-1.1-0.7-1.8-0.8c-0.3-0.1-0.7-0.2-1-0.3c-0.2-0.1-0.3-0.3-0.2-0.5
|
||||
c0-0.2,0.1-0.4,0.2-0.5c0.1-0.2,0.3-0.2,0.6-0.2c0.4-0.1,0.8,0.2,0.8,0.6c0,0.1,0,0.1,0,0.2h1.8c0-0.6-0.2-1.3-0.8-1.7
|
||||
c-0.5-0.4-1.2-0.6-1.9-0.6c-0.7-0.1-1.5,0.2-2,0.7c-0.5,0.4-0.7,1-0.7,1.7c0,0.5,0.2,1,0.6,1.4c0.5,0.4,1.1,0.6,1.7,0.7
|
||||
c0.4,0.1,0.7,0.2,1,0.3c0.2,0.1,0.3,0.3,0.2,0.6c0,0.2-0.1,0.4-0.2,0.5c-0.2,0.2-0.4,0.2-0.7,0.2s-0.5-0.1-0.8-0.2l-0.1-0.2
|
||||
c-0.2-0.3-0.5-0.5-0.8-0.5h-1.2c0,0.7,0.4,1.4,1.1,1.8c0.6,0.4,1.3,0.6,2,0.6c0.4,0,0.7,0,1.1-0.2c0.3-0.1,0.6-0.2,0.9-0.4
|
||||
c0.3-0.2,0.5-0.4,0.6-0.7c0.1-0.3,0.2-0.7,0.2-1.1C1527.3,509.9,1527.1,509.4,1526.8,509z"/>
|
||||
</g>
|
||||
<path class="st1" d="M1334.1,495.3h-9.5v-48.8h9.3v7c3.6-6.1,9.3-8.4,15-8.4c11.7,0,17.5,8.4,17.5,19.3v31h-9.5v-29.3
|
||||
c0-6.8-2.8-12.3-11.4-12.3c-7.5,0-11.4,6-11.4,13.4V495.3z"/>
|
||||
<path class="st1" d="M1460.5,494.5h-9.6l-19.8-48.8h10.8l13.9,37.6l14-37.6h10.2L1460.5,494.5z"/>
|
||||
<path class="st1" d="M1500.3,466.6l13.2-1.9c2.9-0.4,3.8-1.9,3.8-3.7c0-4.8-3.1-8.7-10.6-8.7c-6.7,0-10.5,4.2-11.1,9.8l-9.1-2.1
|
||||
c1-9.3,9.4-15.8,20-15.8c14.6,0,20.3,8.3,20.3,17.9v24.5c0,4.3,0.4,6.8,0.6,8h-9.3c-0.2-1.2-0.5-3-0.5-6.6c-2.1,3.5-7,8.1-15.7,8.1
|
||||
c-9.9,0-16.3-6.9-16.3-14.6C1485.5,472.7,1491.9,467.9,1500.3,466.6z M1517.3,473.6v-2.2l-14.9,2.2c-4.1,0.6-7.1,2.9-7.1,7.3
|
||||
c0,3.7,3,7.1,7.9,7.1C1511,488.1,1517.3,484.3,1517.3,473.6z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M1977.8,504.3c-0.9,0-1.5,0.4-1.7,0.9v-3.4h-1v7.9h1v-0.8c0.3,0.6,0.9,0.9,1.7,0.9c1.6,0,2.4-1.2,2.4-2.8
|
||||
C1980.2,505.5,1979.4,504.3,1977.8,504.3z M1977.6,508.9c-0.9,0-1.6-0.7-1.6-1.9c0-1.1,0.7-1.8,1.6-1.8c1,0,1.6,0.7,1.6,1.8
|
||||
C1979.2,508.1,1978.6,508.9,1977.6,508.9z"/>
|
||||
<polygon class="st1" points="1983.4,508 1981.7,504.4 1980.5,504.4 1982.8,509.1 1981.5,511.9 1982.6,511.9 1986,504.4
|
||||
1984.9,504.4 "/>
|
||||
<path class="st1" d="M1989.4,510h0.9c0.4,0,0.8-0.3,0.8-0.8v-2.8h1.3c0.6,0,1.1-0.5,1.1-1.1v-0.5h-2.4V503h2.6c0.5,0,1-0.4,1-1
|
||||
v-0.6h-5.3V510z"/>
|
||||
<path class="st1" d="M1997.7,503.6c-0.7,0-1.3,0.2-1.7,0.6c-0.5,0.4-0.7,0.9-0.7,1.6h1.6c0-0.2,0.1-0.4,0.3-0.5s0.4-0.2,0.7-0.2
|
||||
s0.5,0,0.7,0.2c0.1,0.2,0.2,0.3,0.2,0.7v0.2l-1.6,0.3c-0.3,0-0.6,0.1-0.8,0.2c-0.2,0.1-0.4,0.2-0.6,0.3c-0.2,0.1-0.3,0.3-0.4,0.5
|
||||
c-0.1,0.2-0.1,0.4-0.1,0.7c0,0.6,0.2,1,0.5,1.3c0.4,0.3,0.8,0.5,1.4,0.5c0.8,0,1.4-0.3,1.8-1v0.2c0,0.4,0.4,0.7,0.8,0.7h0.7v-4.1
|
||||
c0-0.7-0.2-1.3-0.7-1.7S1998.5,503.6,1997.7,503.6z M1998.5,507.4c0,0.3-0.1,0.5-0.2,0.7c-0.1,0.2-0.3,0.3-0.4,0.4
|
||||
c-0.2,0.1-0.3,0.1-0.6,0.1s-0.4,0-0.5-0.1c-0.1-0.1-0.2-0.2-0.2-0.4c0-0.2,0-0.3,0.1-0.4c0.1-0.1,0.3-0.2,0.5-0.2l1.3-0.3V507.4z"
|
||||
/>
|
||||
<path class="st1" d="M2002.6,501c-0.3,0-0.5,0.1-0.7,0.3c-0.2,0.2-0.3,0.4-0.3,0.7s0,0.5,0.3,0.7c0.2,0.2,0.4,0.3,0.7,0.3
|
||||
s0.5-0.1,0.7-0.3c0.2-0.2,0.3-0.4,0.3-0.7s-0.1-0.5-0.3-0.7C2003.1,501.1,2002.8,501,2002.6,501z"/>
|
||||
<path class="st1" d="M2001.8,510h0.8c0.4,0,0.8-0.3,0.8-0.8v-5.5h-1.6V510z"/>
|
||||
<path class="st1" d="M2006.5,504.7l-0.2-1h-1.4v6.2h0.9c0.4,0,0.8-0.3,0.8-0.8v-2.4c0-0.6,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.4,1.2-0.4
|
||||
v-1.6c-0.5,0-0.9,0.1-1.2,0.3C2006.9,504.1,2006.7,504.4,2006.5,504.7z"/>
|
||||
<path class="st1" d="M2015.9,507.5l-0.1,0.7l-0.1-0.7l-1-3.8h-1.4l-1,3.8l-0.1,0.7l-0.1-0.7l-1-3.8h-1.7l1.9,6.2h1
|
||||
c0.3,0,0.7-0.2,0.8-0.6l1-3.1l1.1,3.7h1.1c0.3,0,0.7-0.2,0.8-0.6l1.7-5.6h-1.7L2015.9,507.5z"/>
|
||||
<path class="st1" d="M2020.3,501c-0.3,0-0.5,0.1-0.7,0.3c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.3,0.1,0.5,0.3,0.7c0.2,0.2,0.4,0.3,0.7,0.3
|
||||
s0.5-0.1,0.7-0.3s0.3-0.4,0.3-0.7s-0.1-0.5-0.3-0.7C2020.8,501.1,2020.6,501,2020.3,501z"/>
|
||||
<path class="st1" d="M2019.5,510h0.8c0.4,0,0.8-0.3,0.8-0.8v-5.5h-1.6V510z"/>
|
||||
<path class="st1" d="M2026,503.6c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.5,0.4-0.7,0.7l-0.1-0.8h-1.4v6.2h0.8c0.4,0,0.8-0.3,0.8-0.8v-2.4
|
||||
c0-0.5,0.1-0.9,0.3-1.1s0.4-0.4,0.8-0.4c0.3,0,0.5,0.1,0.7,0.3c0.1,0.2,0.2,0.5,0.2,0.8v3.7h0.8c0.4,0,0.8-0.3,0.8-0.8v-3.2
|
||||
c0-0.7-0.2-1.3-0.5-1.7C2027.2,503.8,2026.7,503.6,2026,503.6z"/>
|
||||
<path class="st1" d="M2034,504.4c-0.2-0.2-0.4-0.4-0.7-0.6c-0.3-0.1-0.7-0.2-1.1-0.2c-0.8,0-1.5,0.3-2.1,0.9
|
||||
c-0.6,0.6-0.8,1.4-0.8,2.3c0,0.6,0.1,1.1,0.3,1.7c0.3,0.5,0.6,0.9,1,1.2s1,0.4,1.5,0.4c0.9,0,1.6-0.3,2-1l0,0.2
|
||||
c0.1,0.3,0.4,0.7,0.8,0.7h0.7v-9h-1.6V504.4z M2033.9,506.9c0,0.5-0.2,1-0.5,1.3c-0.3,0.3-0.7,0.5-1.1,0.5c-0.5,0-0.8-0.1-1.1-0.5
|
||||
c-0.3-0.3-0.4-0.7-0.4-1.3s0.1-1,0.4-1.3s0.7-0.5,1.1-0.5c0.3,0,0.5,0,0.7,0.2c0.2,0.1,0.4,0.3,0.6,0.6
|
||||
C2033.9,506.1,2033.9,506.4,2033.9,506.9L2033.9,506.9z"/>
|
||||
<path class="st1" d="M2041.3,506.9c-0.3-0.3-0.8-0.5-1.6-0.7c-0.4-0.1-0.7-0.2-0.9-0.3c-0.1-0.1-0.2-0.2-0.2-0.4
|
||||
c0-0.2,0-0.3,0.2-0.4c0.1-0.1,0.3-0.2,0.5-0.2c0.4,0,0.7,0.2,0.7,0.7h1.6c0-0.6-0.2-1.1-0.7-1.4c-0.4-0.3-1-0.5-1.6-0.5
|
||||
c-0.7,0-1.3,0.2-1.7,0.6c-0.4,0.4-0.6,0.9-0.6,1.4c0,0.5,0.1,0.9,0.5,1.2c0.3,0.3,0.8,0.5,1.5,0.6c0.4,0.1,0.7,0.2,0.9,0.3
|
||||
c0.1,0.1,0.2,0.3,0.2,0.5c0,0.2-0.1,0.3-0.2,0.4c-0.1,0.1-0.3,0.2-0.6,0.2s-0.5-0.1-0.7-0.2c0,0-0.1-0.1-0.1-0.1
|
||||
c-0.2-0.3-0.4-0.4-0.7-0.4h-1c0,0.6,0.3,1.1,0.9,1.5c0.4,0.3,1,0.5,1.7,0.5c0.3,0,0.6,0,0.9-0.1c0.3,0,0.5-0.2,0.7-0.3
|
||||
c0.2-0.1,0.4-0.3,0.5-0.6s0.2-0.6,0.2-0.9C2041.8,507.6,2041.6,507.2,2041.3,506.9z"/>
|
||||
<g>
|
||||
<path class="st1" d="M2011.4,483.3c0.7,4.7,5.5,12.1,16.9,12.1c10.3,0,15.2-7,15.2-12.9c0-6.1-4-10.7-11.5-12.3l-6.7-1.5
|
||||
c-3.2-0.7-4.8-2.5-4.8-5c0-2.8,2.8-5.5,6.9-5.5c6.6,0,8.3,4.8,8.6,6.9l7.2-2.7c-0.9-3.7-4.4-11.1-15.8-11.1
|
||||
c-8.1,0-14.8,6-14.8,13.1c0,5.9,3.9,10.3,10.4,11.7l7.1,1.6c3.5,0.8,5.4,2.8,5.4,5.4c0,2.9-2.5,5.5-7.1,5.5
|
||||
c-5.9,0-9.2-3.5-9.7-7.8L2011.4,483.3z M2007.1,452.6h-11.2l-18,18.4v-39.4h-8v62.5h8v-12.5l5.8-5.8l13.6,18.3h10.2l-18-24
|
||||
L2007.1,452.6z M1941.6,458.8c7.1,0,10.1,4.7,11.1,8.8l7.3-3.1c-1.7-6.3-7.4-13.2-18.5-13.2c-11.8,0-20.9,9.1-20.9,22
|
||||
c0,12.6,8.9,22.1,21,22.1c10.8,0,16.8-7,18.7-13l-7.2-3.1c-0.9,3.3-3.8,8.6-11.6,8.6c-6.7,0-12.7-5.1-12.7-14.6
|
||||
C1929,463.6,1935,458.8,1941.6,458.8 M1892.5,451.3c-12.4,0-21.2,9.4-21.2,22c0,12.7,8.8,22.1,21.2,22.1
|
||||
c12.4,0,21.2-9.4,21.2-22.1C1913.8,460.7,1905,451.3,1892.5,451.3 M1892.5,488.1c-6.9,0-13-5.2-13-14.9c0-9.6,6-14.8,13-14.8
|
||||
c6.9,0,13,5.2,13,14.8C1905.5,483,1899.4,488.1,1892.5,488.1 M1860.9,431.6h-8.1v62.5h8.1V431.6z M1829.1,436.8
|
||||
c0,3.2,2.6,5.8,5.8,5.8c3.3,0,5.9-2.6,5.9-5.8c0-3.3-2.6-5.9-5.9-5.9C1831.7,431,1829.1,433.6,1829.1,436.8 M1839,452.6h-8v41.5h8
|
||||
V452.6z M1809.3,488.5c0,2.5,0.3,4.7,0.4,5.6h7.9c-0.1-0.7-0.4-3.7-0.4-7.7v-54.8h-8v26.9c-1.4-3.4-5.4-7-12.7-7
|
||||
c-11.7,0-19.7,10-19.7,21.8c0,12.4,7.5,22,19.7,22c6.5,0,10.9-3.5,12.9-7.4V488.5L1809.3,488.5z M1785,473.2
|
||||
c0-8.5,4.8-14.6,12.3-14.6c7.4,0,11.9,5.9,11.9,14.4c0,8.6-4.6,15-12,15C1789.4,488.1,1785,481.7,1785,473.2 M1766.3,431.6h-8.1
|
||||
v62.5h8.1V431.6z M1696.7,494.1v-30h-29.3v7.6h21.2c-0.3,6.3-5.3,16-18.9,16c-11,0-21.3-8-21.3-24.3c0-16.2,10.7-24.1,21.7-24.1
|
||||
c9.5,0,16.7,5.2,19.4,14l7.7-3.3c-3.5-11.1-13.8-18.5-27.1-18.5c-15.1,0-30.3,11.1-30.3,31.9c0,20.7,14.3,32,29.7,32
|
||||
c10.3,0,16.9-5.1,19.6-9.9l0.8,8.6C1689.8,494.1,1696.7,494.1,1696.7,494.1z"/>
|
||||
<g>
|
||||
<path class="st1" d="M1740.6,509.4c-9.3,0-21.3-12.9-29.5-27.8c-4.9-8.8-8.2-17.9-9.5-25.4c-1.8-11.2,1.6-15.6,4.7-17.4
|
||||
c3.1-1.7,8.7-2.3,17.2,5.2c5.8,5,11.7,12.7,16.6,21.5c9.6,17.3,14.3,37.5,4.7,42.8C1743.6,509,1742.1,509.4,1740.6,509.4z
|
||||
M1710.7,444.6c-0.4,0-0.7,0.1-1,0.2c-1.3,0.7-2.2,4.2-1.3,10.3c1.1,6.8,4.2,15,8.7,23.2c10.3,18.6,21.5,25.6,24.4,24
|
||||
c2.9-1.6,2.9-14.9-7.4-33.4c-4.5-8.1-9.9-15.1-15.1-19.6C1715.4,445.9,1712.4,444.6,1710.7,444.6z"/>
|
||||
</g>
|
||||
<polygon class="st6" points="1725.6,495.2 1728.5,497.4 1730.7,494.5 1734,496 1735.4,492.7 1739,493.4 1739.6,489.9
|
||||
1743.2,489.6 1743,486 1746.4,485 1745.4,481.6 1748.4,479.7 1746.6,476.6 1749.1,474.1 1746.6,471.5 1748.4,468.5 1745.4,466.6
|
||||
1746.4,463.2 1743,462.1 1743.2,458.5 1739.6,458.3 1739,454.8 1735.4,455.4 1734,452.1 1730.7,453.6 1728.5,450.8 1725.6,453
|
||||
1722.8,450.8 1720.6,453.6 1717.3,452.1 1715.9,455.4 1712.3,454.8 1711.7,458.3 1708.1,458.5 1708.3,462.1 1704.9,463.2
|
||||
1705.9,466.6 1702.9,468.5 1704.7,471.5 1702.2,474.1 1704.7,476.6 1702.9,479.7 1705.9,481.6 1704.9,485 1708.3,486.1
|
||||
1708.1,489.6 1711.7,489.9 1712.3,493.4 1715.9,492.7 1717.3,496 1720.6,494.5 1722.8,497.4 "/>
|
||||
<g>
|
||||
<path class="st7" d="M1725.6,491.9c9.8,0,17.8-8,17.8-17.8c0-9.8-8-17.8-17.8-17.8c-9.8,0-17.8,8-17.8,17.8
|
||||
C1707.8,483.9,1715.8,491.9,1725.6,491.9"/>
|
||||
<g>
|
||||
<path class="st1" d="M1740.6,509.4c-9.6,0-21.7-13.7-29.5-27.8c-4.9-8.8-8.2-17.9-9.5-25.4c-1.8-11.2,1.6-15.6,4.7-17.4l3.3,6
|
||||
c-1.3,0.7-2.2,4.2-1.3,10.3c1.1,6.8,4.2,15,8.7,23.2c9.3,16.9,20.4,25.4,24.2,24.1l2.2,6.5
|
||||
C1742.6,509.2,1741.6,509.4,1740.6,509.4z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M2177.7,512.3v-64.9h8.8v7.2c2.5-4.7,8.1-8.3,15.6-8.3c13.9,0,21.4,10.7,21.4,24.3c0,13.9-8,24.6-21.7,24.6
|
||||
c-7.1,0-12.6-3.4-15.1-7.5v24.7L2177.7,512.3L2177.7,512.3z M2200.4,454.3c-8.3,0-13.9,7-13.9,16.3c0,9.6,5.5,16.4,13.9,16.4
|
||||
c8.4,0,13.8-6.9,13.8-16.4C2214.2,461.3,2208.9,454.3,2200.4,454.3z"/>
|
||||
<path class="st1" d="M2235.1,493.9v-70h9.1v70.1L2235.1,493.9L2235.1,493.9z"/>
|
||||
<path class="st1" d="M2276.1,495.3c-10.8,0-17.4-8.1-17.4-18.7v-29.3h9.1v27.9c0,6.4,2.9,12,10.5,12c7.3,0,11-4.9,11-11.9v-28h9.1
|
||||
v38c0,3.7,0.3,7,0.5,8.6h-8.7c-0.2-1.1-0.4-3.7-0.4-5.6C2287.3,493.1,2281.5,495.3,2276.1,495.3z"/>
|
||||
<path class="st1" d="M2326.2,447.4h10.1v8.2h-10.1v24.2c0,4.3,1.7,6.4,6.5,6.4c1.2,0,2.8-0.2,3.6-0.4v7.7c-0.8,0.3-3.1,0.9-6.2,0.9
|
||||
c-7.9,0-13-4.9-13-13.3v-25.5h-8.9v-8.2h2.5c5.1,0,7.1-3.1,7.1-7.1v-7.6h8.3V447.4z"/>
|
||||
<rect x="2353.9" y="456.8" class="st8" width="26.1" height="26.1"/>
|
||||
<g id="XMLID_3_">
|
||||
<g>
|
||||
<path class="st1" d="M2367.8,445.7c15.1,0,25.8,10.5,25.8,24.7c0,14.2-10.7,24.8-25.8,24.8c-15.1,0-25.8-10.5-25.8-24.8
|
||||
C2342,456.2,2352.7,445.7,2367.8,445.7z M2384.9,470.1c0-9.4-7.7-17.1-17.1-17.1s-17.1,7.7-17.1,17.1c0,9.4,7.7,17.1,17.1,17.1
|
||||
C2377.2,487.2,2384.9,479.6,2384.9,470.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M2320.6,504.5c-1,0-1.7,0.5-1.9,1v-3.8h-1.1v8.8h1.1v-0.9c0.4,0.6,1,1,1.9,1c1.7,0,2.7-1.4,2.7-3.1
|
||||
C2323.3,505.9,2322.4,504.5,2320.6,504.5z M2320.4,509.7c-1,0-1.7-0.8-1.7-2.1c0-1.3,0.7-2.1,1.7-2.1c1.1,0,1.7,0.8,1.7,2.1
|
||||
C2322.1,508.9,2321.4,509.7,2320.4,509.7z"/>
|
||||
<polygon class="st1" points="2326.8,508.7 2324.9,504.7 2323.6,504.7 2326.1,509.9 2324.7,513 2325.9,513 2329.7,504.7
|
||||
2328.5,504.7 "/>
|
||||
<path class="st1" d="M2333.4,510.9h1c0.5,0,0.9-0.4,0.9-0.9V507h1.5c0.7,0,1.2-0.6,1.2-1.2v-0.5h-2.7v-2.1h2.9
|
||||
c0.6,0,1.1-0.5,1.1-1.1v-0.7h-5.9V510.9z"/>
|
||||
<path class="st1" d="M2342.7,503.8c-0.8,0-1.5,0.2-1.9,0.7c-0.5,0.4-0.8,1-0.8,1.7h1.7c0-0.2,0.1-0.4,0.3-0.6s0.4-0.2,0.7-0.2
|
||||
c0.3,0,0.6,0,0.7,0.2c0.1,0.2,0.2,0.4,0.2,0.7v0.2l-1.8,0.3c-0.3,0-0.6,0.1-0.9,0.2c-0.2,0.1-0.5,0.2-0.7,0.4
|
||||
c-0.2,0.1-0.4,0.3-0.5,0.6s-0.1,0.5-0.1,0.8c0,0.6,0.2,1.2,0.6,1.5c0.4,0.4,0.9,0.6,1.6,0.6c0.9,0,1.6-0.3,2-1.1v0.2
|
||||
c0,0.4,0.4,0.8,0.9,0.8h0.7v-4.6c0-0.8-0.2-1.5-0.7-1.9C2344.2,504,2343.6,503.8,2342.7,503.8z M2343.7,508c0,0.3-0.1,0.6-0.2,0.8
|
||||
c-0.1,0.2-0.3,0.3-0.5,0.4c-0.2,0.1-0.4,0.1-0.6,0.1c-0.2,0-0.4,0-0.6-0.1c-0.1-0.1-0.2-0.2-0.2-0.4c0-0.2,0-0.4,0.1-0.5
|
||||
c0.1-0.1,0.3-0.2,0.6-0.2l1.4-0.3V508z"/>
|
||||
<path class="st1" d="M2348.1,500.9c-0.3,0-0.5,0.1-0.7,0.3c-0.2,0.2-0.3,0.5-0.3,0.8c0,0.3,0,0.5,0.3,0.7c0.2,0.2,0.5,0.3,0.8,0.3
|
||||
c0.3,0,0.6-0.1,0.8-0.3c0.2-0.2,0.3-0.4,0.3-0.7c0-0.3-0.1-0.6-0.3-0.8C2348.7,501,2348.4,500.9,2348.1,500.9z"/>
|
||||
<path class="st1" d="M2347.2,510.9h0.9c0.5,0,0.9-0.4,0.9-0.9V504h-1.8V510.9z"/>
|
||||
<path class="st1" d="M2352.5,505l-0.2-1.1h-1.6v7h1c0.5,0,0.9-0.4,0.9-0.9v-2.7c0-0.6,0.2-1,0.5-1.3c0.3-0.3,0.8-0.4,1.4-0.4v-1.7
|
||||
c-0.5,0-1,0.1-1.3,0.3C2352.9,504.4,2352.7,504.7,2352.5,505z"/>
|
||||
<path class="st1" d="M2362.9,508.2l-0.1,0.7l-0.1-0.7l-1.2-4.2h-1.6l-1.2,4.2l-0.1,0.7l-0.1-0.7l-1.1-4.2h-1.9l2.1,6.9h1.1
|
||||
c0.4,0,0.7-0.2,0.9-0.6l1.1-3.5l1.3,4.1h1.2c0.4,0,0.8-0.2,0.9-0.6l1.9-6.3h-1.9L2362.9,508.2z"/>
|
||||
<path class="st1" d="M2367.9,500.9c-0.3,0-0.6,0.1-0.8,0.3c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.3,0.1,0.6,0.3,0.7
|
||||
c0.2,0.2,0.5,0.3,0.8,0.3c0.3,0,0.5-0.1,0.8-0.3c0.2-0.2,0.3-0.4,0.3-0.7s-0.1-0.5-0.3-0.7C2368.4,501,2368.2,500.9,2367.9,500.9z
|
||||
"/>
|
||||
<path class="st1" d="M2367,510.9h0.9c0.5,0,0.9-0.4,0.9-0.9V504h-1.8V510.9z"/>
|
||||
<path class="st1" d="M2374.2,503.8c-0.5,0-0.8,0.1-1.2,0.3c-0.3,0.2-0.5,0.4-0.7,0.8l-0.1-0.9h-1.6v7h0.9c0.5,0,0.9-0.4,0.9-0.9
|
||||
v-2.7c0-0.6,0.1-1,0.3-1.3s0.5-0.4,0.9-0.4c0.3,0,0.6,0.1,0.7,0.3c0.1,0.2,0.2,0.5,0.2,0.9v4.1h0.9c0.5,0,0.9-0.4,0.9-0.9v-3.6
|
||||
c0-0.8-0.2-1.4-0.6-1.9C2375.5,504,2375,503.8,2374.2,503.8z"/>
|
||||
<path class="st1" d="M2383.1,504.7c-0.2-0.2-0.4-0.4-0.8-0.6c-0.4-0.1-0.8-0.2-1.3-0.2c-0.9,0-1.7,0.3-2.3,1
|
||||
c-0.6,0.7-0.9,1.6-0.9,2.6c0,0.7,0.1,1.3,0.4,1.8c0.3,0.6,0.7,1,1.2,1.3c0.5,0.3,1.1,0.5,1.7,0.5c1,0,1.7-0.3,2.2-1.1l0,0.2
|
||||
c0.1,0.4,0.4,0.7,0.9,0.7h0.8v-10h-1.8V504.7z M2383,507.5c0,0.6-0.2,1.1-0.5,1.4s-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.1-1.3-0.5
|
||||
c-0.3-0.3-0.5-0.8-0.5-1.4s0.1-1.1,0.5-1.4c0.3-0.3,0.8-0.5,1.3-0.5c0.3,0,0.6,0,0.8,0.2c0.2,0.1,0.4,0.3,0.6,0.6
|
||||
C2382.9,506.6,2383,507,2383,507.5L2383,507.5z"/>
|
||||
<path class="st1" d="M2391.2,507.5c-0.3-0.3-0.9-0.6-1.7-0.7c-0.5-0.1-0.8-0.2-1-0.3c-0.1-0.1-0.2-0.2-0.2-0.5
|
||||
c0-0.2,0-0.3,0.2-0.5c0.1-0.1,0.3-0.2,0.5-0.2c0.5,0,0.8,0.2,0.8,0.8h1.7c0-0.7-0.2-1.2-0.7-1.6c-0.4-0.4-1.1-0.6-1.8-0.6
|
||||
c-0.8,0-1.5,0.2-1.9,0.6c-0.4,0.4-0.7,1-0.7,1.6c0,0.6,0.1,1,0.5,1.4c0.3,0.3,0.9,0.5,1.7,0.7c0.4,0.1,0.8,0.2,1,0.3
|
||||
c0.1,0.1,0.2,0.3,0.2,0.5c0,0.2-0.1,0.4-0.2,0.5c-0.1,0.1-0.3,0.2-0.6,0.2c-0.3,0-0.5-0.1-0.7-0.2c0,0-0.1-0.1-0.1-0.1
|
||||
c-0.2-0.3-0.4-0.5-0.8-0.5h-1.1c0,0.7,0.3,1.3,1,1.7c0.4,0.4,1.1,0.6,1.9,0.6c0.4,0,0.7,0,1-0.1c0.3,0,0.6-0.2,0.8-0.4
|
||||
c0.2-0.1,0.4-0.4,0.6-0.7s0.2-0.6,0.2-1C2391.8,508.2,2391.6,507.8,2391.2,507.5z"/>
|
||||
</g>
|
||||
<path class="st9" d="M2379,461.3c-0.1,0.1-0.1,0.1-0.1,0.2c-0.1,0.5-0.4,0.9-0.6,1.4c-0.3,0.8,0.1,2.7-0.7,3.2
|
||||
c-1,0.6-2.1-1.3-3-2.1c-0.9-0.8-2.5-0.4-3.6-0.7c-0.9-0.2-1.8-0.9-2.8-0.6c-0.8,0.2-1.6,1.3-2.4,1.6c0-0.4,0-0.8-0.4-0.5
|
||||
c-0.9,0.7-1.6,1.5-2.5,2.1c-0.1,0.1-0.1-0.1-0.2,0c-0.1,0.2-1.2,0.1-1.2,0.4c0,1-0.1,2.4-1,2.8c-0.1,0-0.4-1.4-0.5-1.5
|
||||
c-0.1,0-0.9,1-1,0.8c-0.7-0.8-1.3-1.2-2.3-1.7c-0.5-0.3-1.8,0.6-2.2,0.2c-0.1-0.1-0.2-0.2-0.3-0.3c-0.3,1.2-0.5,2.5-0.5,3.7
|
||||
c0,7.9,6.4,14.3,14.3,14.3c7.9,0,14.3-6.4,14.3-14.3C2382.2,466.8,2381,463.7,2379,461.3z"/>
|
||||
<path class="st1" d="M2361.5,466.1c0,1-0.1,2.4-1,2.8c-0.1,0-0.4-1.4-0.5-1.5c-0.1,0-0.9,1-1,0.8c-0.7-0.8-1.3-1.2-2.3-1.7
|
||||
c-0.5-0.3-1.8,0.6-2.2,0.2c-0.1-0.1-0.2-0.2-0.3-0.3c1.7-6.1,7.2-10.5,13.8-10.5c4.5,0,8.5,2.1,11.1,5.3c0,0.1-0.1,0.1-0.1,0.2
|
||||
c-0.1,0.5-0.4,0.9-0.6,1.4c-0.3,0.8,0,2.7-0.7,3.2c-1,0.6-2.1-1.3-3-2.1c-0.9-0.8-2.5-0.4-3.6-0.7c-0.9-0.2-1.8-0.9-2.8-0.6
|
||||
c-0.8,0.2-1.6,1.3-2.4,1.6c0-0.4,0-0.8-0.4-0.5c-0.9,0.7-1.7,1.5-2.5,2.1c-0.1,0.1-0.1-0.1-0.2,0
|
||||
C2362.6,466,2361.5,465.9,2361.5,466.1z"/>
|
||||
<path class="st1" d="M2376.5,472.6c-1.1-0.2-2.1,0.1-2.9,0.8c-0.4-0.9-1.3-1.7-2.4-1.9c-1.8-0.4-3.6,0.8-3.9,2.6
|
||||
c-0.7,3.6,3.9,8.1,4.1,8.3c0.1,0.1,0.2,0.1,0.3,0.2c0.1,0,0.2,0,0.4,0c0.2-0.1,6.3-2.4,7-6C2379.5,474.8,2378.4,473,2376.5,472.6z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st10">
|
||||
<path class="st11" d="M611.3,540V410.3h17.6v14.5c5-9.3,16.1-16.6,31.1-16.6c27.8,0,42.7,21.5,42.7,48.5
|
||||
c0,27.7-16.1,49.1-43.3,49.1c-14.3,0-25.1-6.8-30.2-15.1V540H611.3z M656.8,424.2c-16.6,0-27.7,13.9-27.7,32.5
|
||||
c0,19.1,11,32.9,27.7,32.9c16.8,0,27.5-13.7,27.5-32.9C684.2,438.1,673.8,424.2,656.8,424.2z"/>
|
||||
<path class="st11" d="M813.4,456.7c0,28.4-19.7,49.5-47.6,49.5c-27.8,0-47.6-21.1-47.6-49.5c0-28.2,19.7-49.3,47.6-49.3
|
||||
C793.7,407.4,813.4,428.4,813.4,456.7z M794.8,456.7c0-21.5-13.5-33.1-29-33.1c-15.5,0-29,11.6-29,33.1c0,21.7,13.5,33.3,29,33.3
|
||||
C781.3,489.9,794.8,478.3,794.8,456.7z"/>
|
||||
<path class="st11" d="M836.6,503.3v-140h18.2v140H836.6z"/>
|
||||
<path class="st11" d="M908.2,450.1l25.1-3.7c5.6-0.8,7.2-3.7,7.2-7c0-9.1-6-16.6-20.1-16.6c-12.8,0-19.9,7.9-21.1,18.8l-17.4-4.1
|
||||
c1.9-17.8,18-30.2,38.1-30.2c27.8,0,38.7,15.9,38.7,34V488c0,8.1,0.8,13,1.2,15.3H942c-0.4-2.3-1-5.8-1-12.6
|
||||
c-4.1,6.6-13.3,15.5-30,15.5c-19,0-31.1-13.1-31.1-27.8C879.9,461.7,892.1,452.4,908.2,450.1z M940.5,463.4v-4.3l-28.4,4.3
|
||||
c-7.7,1.2-13.5,5.6-13.5,13.9c0,7,5.8,13.5,15.1,13.5C928.5,490.9,940.5,483.7,940.5,463.4z"/>
|
||||
<path class="st11" d="M1038.5,428.6c-2.7-0.4-5.4-0.6-7.9-0.6c-15.3,0-25.5,8.1-25.5,28.6v46.6h-18.2v-93h17.8v16.2
|
||||
c6.8-14.3,18.4-17.8,27.8-17.8c2.5,0,5,0.4,6,0.6V428.6z"/>
|
||||
<path class="st11" d="M1066.7,361.9c7.3,0,13.2,5.8,13.2,13.1c0,7.2-5.8,13-13.2,13c-7.2,0-13-5.8-13-13
|
||||
C1053.8,367.7,1059.6,361.9,1066.7,361.9z M1057.8,503.3v-93h18v93H1057.8z"/>
|
||||
<path class="st11" d="M1114.5,473.3c1.2,9.7,8.5,17.4,21.7,17.4c10.2,0,15.9-5.8,15.9-12.4c0-5.8-4.3-10.2-12-12l-15.9-3.5
|
||||
c-14.5-3.1-23.2-13-23.2-26.1c0-15.9,14.9-29.4,33.1-29.4c25.5,0,33.5,16.6,35.4,24.9l-16.1,6c-0.8-4.8-4.6-15.5-19.3-15.5
|
||||
c-9.3,0-15.5,6-15.5,12.4c0,5.6,3.5,9.7,10.6,11.2l15.1,3.3c16.8,3.7,25.7,13.9,25.7,27.7c0,13.1-11,28.8-34,28.8
|
||||
c-25.5,0-36.4-16.4-37.9-27.1L1114.5,473.3z"/>
|
||||
</g>
|
||||
<circle class="st11" cx="765.9" cy="456.2" r="49.7"/>
|
||||
<circle class="st12" cx="787.6" cy="478.1" r="2.8"/>
|
||||
<circle class="st12" cx="744.8" cy="478.5" r="2.8"/>
|
||||
<g>
|
||||
<path class="st13" d="M750.9,431.5c0.6,0.8,1.2,1.6,1.7,2.3c3,3.8,5.9,7.7,8.9,11.5c0.3,0.3,0.3,0.8,0.2,1.1
|
||||
c-0.9,1.5-1.8,3-2.7,4.5c-1.3,2-2.5,4.2-3.8,6.2c0,0,0,0.1-0.1,0.2c0.6-0.4,1.2-0.7,1.7-1.1c3-1.8,6-3.7,9-5.5
|
||||
c0.4-0.2,0.8-0.1,1.3,0.2c2.8,2.1,5.6,4.4,8.4,6.5c1.7,1.3,3.2,2.5,4.9,3.8c0.1,0.1,0.2,0.2,0.4,0.2c-3.6-4.6-7.1-9.1-10.7-13.7
|
||||
c-0.3-0.4-0.4-0.8-0.2-1.1c1.1-1.8,2.2-3.6,3.3-5.4c1.1-1.7,2.2-3.6,3.2-5.4c-0.4,0.2-0.7,0.4-1.1,0.7c-2.2,1.4-4.5,2.7-6.7,4.1
|
||||
c-1,0.6-1.9,1.2-3,1.8c-0.4,0.3-0.8,0.2-1.3-0.2c-3.1-2.4-6.1-4.8-9.2-7.2C753.9,433.7,752.5,432.6,750.9,431.5
|
||||
C751,431.5,750.9,431.5,750.9,431.5z"/>
|
||||
<path class="st14" d="M772.7,439.7c-0.4,0.3-0.7,0.5-1.1,0.8c-1.8,1.3-3.6,2.5-5.4,3.8c-0.2,0.1-0.4,0.1-0.6,0
|
||||
c-0.9-0.6-1.7-1.3-2.6-1.8c-1.3-0.9-2.5-1.7-3.7-2.6c0,0,0,0-0.1-0.1c0.3,0.4,0.5,0.7,0.7,1.1c1.3,1.8,2.5,3.6,3.8,5.4
|
||||
c0.2,0.2,0.1,0.4,0,0.7c-1,1.4-1.8,2.6-2.8,4c-0.6,0.8-1.1,1.6-1.7,2.3c0,0.1-0.1,0.1-0.1,0.2c2.1-1.6,4.3-3,6.5-4.6
|
||||
c0.2-0.1,0.4-0.1,0.6,0c1.1,0.8,2.1,1.6,3.2,2.2c1.1,0.8,2.1,1.6,3.2,2.2c-0.2-0.2-0.3-0.4-0.5-0.7c-1-1.4-1.8-2.6-2.8-4
|
||||
c-0.4-0.6-0.9-1.2-1.3-1.7c-0.2-0.2-0.2-0.4,0-0.7c1.1-1.5,2-2.9,3.1-4.4C771.7,441,772.2,440.3,772.7,439.7L772.7,439.7z"/>
|
||||
<path class="st14" d="M765.9,434.5c-0.1,0.6-0.2,1.1-0.3,1.7c-0.5,2.7-1,5.4-1.4,8.2c0,0.2-0.3,0.5-0.5,0.5
|
||||
c-1.4,0.2-2.7,0.5-4,0.7c-1.8,0.3-3.7,0.7-5.6,1c0,0-0.1,0-0.2,0.1c0.6,0.1,1.1,0.2,1.6,0.3c2.7,0.5,5.4,1,8.2,1.5
|
||||
c0.3,0.1,0.5,0.3,0.6,0.6c0.4,2,0.7,4,1.1,6c0.2,1.2,0.4,2.3,0.6,3.5c0,0.1,0,0.2,0.1,0.3c0.6-3.3,1.2-6.5,1.7-9.8
|
||||
c0-0.3,0.3-0.5,0.5-0.5c1.7-0.3,3.2-0.6,4.9-0.9c1.7-0.3,3.2-0.6,4.9-0.9c-0.3-0.1-0.7-0.1-1-0.2c-2-0.4-4-0.7-6-1.1
|
||||
c-0.9-0.2-1.7-0.3-2.7-0.5c-0.4-0.1-0.6-0.2-0.6-0.6c-0.4-2.2-0.8-4.4-1.2-6.6C766.2,436.6,766.1,435.5,765.9,434.5L765.9,434.5z"
|
||||
/>
|
||||
<path class="st15" d="M765.9,439.7c-0.1,0.3-0.1,0.6-0.2,0.9c-0.3,1.6-0.5,3.1-0.8,4.7c0,0.1-0.2,0.3-0.3,0.3
|
||||
c-0.8,0.1-1.6,0.3-2.2,0.4c-1.1,0.2-2.1,0.4-3.2,0.6c0,0,0,0-0.1,0c0.3,0.1,0.6,0.1,0.9,0.2c1.6,0.3,3.1,0.5,4.7,0.8
|
||||
c0.2,0,0.3,0.2,0.3,0.3c0.2,1.2,0.4,2.2,0.6,3.4c0.1,0.7,0.2,1.4,0.3,1.9v0.1c0.3-1.8,0.7-3.7,1-5.5c0-0.2,0.1-0.3,0.3-0.3
|
||||
c0.9-0.2,1.8-0.3,2.7-0.5c0.9-0.2,1.8-0.3,2.7-0.5c-0.2,0-0.4-0.1-0.6-0.1c-1.2-0.2-2.2-0.4-3.4-0.6c-0.5-0.1-1-0.2-1.6-0.3
|
||||
c-0.2,0-0.3-0.1-0.4-0.3c-0.2-1.3-0.4-2.5-0.7-3.7C766.1,440.8,766,440.3,765.9,439.7L765.9,439.7z"/>
|
||||
</g>
|
||||
<path class="st16" d="M748.6,465.4l-13.1,10.8c-0.8,0.7-0.4,1.9,0.7,1.9h26.2c1.1,0,1.6-1.4,0.7-1.9l-13.1-10.8
|
||||
C749.5,465.1,749,465.1,748.6,465.4z"/>
|
||||
<path class="st16" d="M782.8,465.4l-13.1,10.8c-0.8,0.7-0.4,1.9,0.7,1.9h26.2c1.1,0,1.6-1.4,0.7-1.9l-13.1-10.8
|
||||
C783.7,465.1,783.1,465.1,782.8,465.4z"/>
|
||||
<path class="st17" d="M764.7,462.4l-23.1,18.9c-1.5,1.2-0.6,3.5,1.3,3.5h46.2c1.8,0,2.7-2.3,1.3-3.5l-23.1-18.9
|
||||
C766.4,461.8,765.4,461.8,764.7,462.4z"/>
|
||||
<path class="st18" d="M765,471.8l-17.7,14.5c-1.1,0.9-0.5,2.7,1,2.7h35.4c1.5,0,2-1.7,1-2.7l-17.8-14.5
|
||||
C766.3,471.3,765.5,471.3,765,471.8z"/>
|
||||
<path class="st17" d="M765.2,474.7l-14.8,12c-0.9,0.8-0.4,2.2,0.8,2.2h29.4c1.2,0,1.7-1.5,0.8-2.2l-14.6-12
|
||||
C766.3,474.3,765.7,474.3,765.2,474.7z"/>
|
||||
<circle class="st19" cx="765.9" cy="456.2" r="34.9"/>
|
||||
<g>
|
||||
<path class="st20" d="M1020.6,524.4c-2,0-3.4,1-3.9,2v-7.7h-2.3v18h2.3V535c0.7,1.3,2.1,2.1,3.9,2.1c3.5,0,5.6-2.8,5.6-6.3
|
||||
C1026,527.2,1024.2,524.4,1020.6,524.4z M1020.1,534.9c-2.1,0-3.5-1.7-3.5-4.3c0-2.6,1.5-4.2,3.5-4.2c2.2,0,3.5,1.6,3.5,4.2
|
||||
C1023.7,533.2,1022.3,534.9,1020.1,534.9z"/>
|
||||
<polygon class="st20" points="1033.2,533 1029.5,524.8 1026.8,524.8 1031.9,535.4 1028.9,541.7 1031.5,541.7 1039.2,524.8
|
||||
1036.7,524.8 "/>
|
||||
<path class="st20" d="M1046.8,537.4h2.1c1,0,1.8-0.8,1.8-1.8v-6.3h3c1.4,0,2.5-1.2,2.5-2.5v-1.1h-5.5v-4.4h6c1.2,0,2.2-1,2.2-2.2
|
||||
v-1.4h-12V537.4z"/>
|
||||
<path class="st20" d="M1065.8,522.9c-1.6,0-3,0.5-4,1.4c-1.1,0.9-1.6,2.1-1.7,3.6h3.6c0-0.5,0.2-0.9,0.6-1.2
|
||||
c0.4-0.3,0.9-0.5,1.5-0.5c0.6,0,1.2,0.1,1.5,0.5c0.3,0.4,0.5,0.8,0.5,1.5v0.5l-3.7,0.7c-0.7,0.1-1.3,0.2-1.8,0.4
|
||||
c-0.5,0.2-1,0.5-1.4,0.8c-0.5,0.3-0.8,0.7-1,1.2s-0.3,1-0.3,1.7c0,1.3,0.5,2.4,1.2,3c0.9,0.8,1.9,1.2,3.2,1.2
|
||||
c1.8,0,3.2-0.7,4.1-2.2v0.4c0.1,0.9,0.9,1.6,1.8,1.6h1.5v-9.3c0-1.7-0.5-3-1.5-3.9C1068.8,523.3,1067.5,522.9,1065.8,522.9z
|
||||
M1067.7,531.6c0,0.6-0.2,1.2-0.5,1.7c-0.3,0.4-0.6,0.7-1,0.9c-0.4,0.2-0.8,0.3-1.3,0.3c-0.5,0-0.9-0.1-1.2-0.3
|
||||
c-0.3-0.2-0.4-0.5-0.4-0.9c0-0.5,0.1-0.8,0.3-1c0.3-0.2,0.7-0.4,1.2-0.5l2.9-0.6V531.6z"/>
|
||||
<path class="st20" d="M1076.8,517c-0.6,0-1.1,0.2-1.5,0.6c-0.5,0.4-0.7,1-0.7,1.6c0,0.6,0.1,1.1,0.6,1.5c0.5,0.4,1,0.6,1.6,0.6
|
||||
c0.6,0,1.2-0.2,1.6-0.6c0.5-0.4,0.7-0.9,0.7-1.5c0-0.6-0.2-1.2-0.7-1.6C1078,517.2,1077.4,517,1076.8,517z"/>
|
||||
<path class="st20" d="M1075,537.4h1.9c1,0,1.8-0.8,1.8-1.8v-12.4h-3.7V537.4z"/>
|
||||
<path class="st20" d="M1085.8,525.4l-0.4-2.2h-3.2v14.2h2c1,0,1.8-0.8,1.8-1.8v-5.5c0-1.3,0.4-2.1,1.1-2.7
|
||||
c0.7-0.6,1.7-0.9,2.8-0.9V523c-1.1,0-2,0.2-2.7,0.7C1086.6,524.1,1086.1,524.7,1085.8,525.4z"/>
|
||||
<path class="st20" d="M1107.1,531.9l-0.3,1.5l-0.3-1.5l-2.4-8.5h-3.3l-2.4,8.5l-0.3,1.5l-0.3-1.5l-2.2-8.5h-3.9l4.3,14.1h2.3
|
||||
c0.8,0,1.5-0.5,1.8-1.3l2.3-7l2.6,8.3h2.5c0.8,0,1.6-0.5,1.8-1.3l3.9-12.8h-3.9L1107.1,531.9z"/>
|
||||
<path class="st20" d="M1117.2,517c-0.6,0-1.2,0.2-1.6,0.6c-0.5,0.4-0.7,0.9-0.7,1.5c0,0.7,0.2,1.2,0.7,1.5c0.5,0.4,1,0.6,1.6,0.6
|
||||
c0.6,0,1.1-0.2,1.6-0.6c0.5-0.4,0.7-0.9,0.7-1.5c0-0.6-0.3-1.1-0.7-1.5C1118.3,517.2,1117.8,517,1117.2,517z"/>
|
||||
<path class="st20" d="M1115.3,537.4h1.9c1,0,1.8-0.8,1.8-1.8v-12.4h-3.7V537.4z"/>
|
||||
<path class="st20" d="M1130.1,522.9c-1,0-1.7,0.2-2.4,0.6c-0.6,0.4-1.1,0.9-1.5,1.6l-0.3-1.9h-3.2v14.2h1.9c1,0,1.9-0.8,1.9-1.9
|
||||
V530c0-1.2,0.2-2,0.7-2.6s1-0.9,1.8-0.9c0.6,0,1.2,0.3,1.5,0.7c0.3,0.4,0.5,1.1,0.5,1.9v8.3h1.8c1,0,1.9-0.8,1.9-1.9v-7.3
|
||||
c0-1.7-0.4-2.9-1.2-3.9C1132.7,523.4,1131.6,522.9,1130.1,522.9z"/>
|
||||
<path class="st20" d="M1148.1,524.8c-0.4-0.5-0.9-0.9-1.7-1.3c-0.8-0.3-1.6-0.5-2.6-0.5c-1.9,0-3.5,0.7-4.8,2.1
|
||||
c-1.3,1.4-1.9,3.2-1.9,5.3c0,1.4,0.3,2.6,0.8,3.8c0.6,1.2,1.4,2,2.4,2.7c1,0.7,2.2,1,3.4,1c2.1,0,3.6-0.7,4.6-2.2l0.1,0.4
|
||||
c0.2,0.8,0.9,1.5,1.8,1.5h1.6v-20.4h-3.7V524.8z M1148,530.4c0,1.2-0.4,2.2-1.1,2.9c-0.7,0.7-1.5,1.1-2.5,1.1
|
||||
c-1.1,0-1.9-0.3-2.6-1.1c-0.7-0.7-1-1.7-1-2.9s0.3-2.2,1-2.9s1.6-1.1,2.6-1.1c0.6,0,1.2,0.1,1.7,0.4c0.5,0.2,0.9,0.7,1.3,1.3
|
||||
c0.4,0.6,0.6,1.3,0.6,2.1V530.4z"/>
|
||||
<path class="st20" d="M1164.8,530.4c-0.7-0.7-1.9-1.2-3.6-1.5c-1-0.2-1.6-0.4-2-0.6c-0.3-0.2-0.5-0.5-0.5-1c0-0.4,0.1-0.7,0.4-1
|
||||
c0.2-0.3,0.6-0.4,1.1-0.4c1,0,1.6,0.5,1.6,1.6h3.6c0-1.4-0.5-2.5-1.5-3.3c-0.9-0.8-2.2-1.2-3.7-1.2c-1.7,0-3,0.4-3.9,1.3
|
||||
c-0.9,0.9-1.4,2-1.4,3.3c0,1.2,0.3,2.1,1.1,2.8c0.7,0.6,1.8,1.1,3.4,1.4c0.9,0.2,1.6,0.4,2,0.7c0.3,0.3,0.5,0.6,0.5,1.1
|
||||
c0,0.4-0.2,0.8-0.5,1c-0.3,0.3-0.7,0.4-1.3,0.4c-0.6,0-1.1-0.2-1.5-0.5c-0.1-0.1-0.2-0.2-0.3-0.3c-0.4-0.6-0.9-1-1.6-1h-2.3
|
||||
c0.1,1.4,0.6,2.6,2.1,3.5c0.9,0.8,2.3,1.2,4,1.2c0.8,0,1.4-0.1,2.1-0.3c0.6-0.1,1.2-0.4,1.7-0.8c0.5-0.3,0.9-0.8,1.2-1.4
|
||||
s0.4-1.3,0.4-2.1C1165.9,532,1165.5,531.1,1164.8,530.4z"/>
|
||||
</g>
|
||||
</g>
|
||||
<radialGradient id="SVGID_1_" cx="1402.3696" cy="470.6803" r="16.1424" fx="1402.6445" fy="471.3849" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color:#FFF7F2"/>
|
||||
<stop offset="1" style="stop-color:#6D6D6D"/>
|
||||
</radialGradient>
|
||||
<circle class="st27" cx="1402.4" cy="470.7" r="16.1"/>
|
||||
<path class="st1" d="M1402.4,442.2c17.3,0,29.6,12.1,29.6,28.4c0,16.3-12.3,28.5-29.6,28.5s-29.6-12.1-29.6-28.5
|
||||
S1385.1,442.2,1402.4,442.2z M1422,470.4c0-10.9-8.8-19.7-19.7-19.7c-10.9,0-19.7,8.8-19.7,19.7c0,10.9,8.8,19.7,19.7,19.7
|
||||
c0,0,0,0,0,0C1413.2,490,1422,481.2,1422,470.4L1422,470.4z"/>
|
||||
<radialGradient id="SVGID_2_" cx="1402.3696" cy="470.6803" r="21.6422" fx="1402.7382" fy="471.625" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color:#FFF7F2"/>
|
||||
<stop offset="1" style="stop-color:#6D6D6D"/>
|
||||
</radialGradient>
|
||||
<polygon class="st28" points="1406.9,470.7 1406.9,470.6 1406.9,470.7 1425.5,450.6 1402.4,466.2 1402.4,466.2 1379.2,450.6
|
||||
1397.8,470.7 1379.2,490.7 1402.4,475.2 1402.3,475.1 1402.4,475.1 1402.4,475.2 1425.5,490.7 1406.9,470.7 "/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 186 KiB |
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 486.5 92.3" style="enable-background:new 0 0 486.5 92.3;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M72.5,24.3H0.4V0.4h84.4V12C84.8,18.8,79.3,24.3,72.5,24.3z"/>
|
||||
<path class="st0" d="M41.8,58H0.4V34.1h53.7v11.6C54.1,52.5,48.6,58,41.8,58z"/>
|
||||
<path class="st0" d="M12,91.7H0.4V67.8h23.9v11.6C24.2,86.2,18.7,91.7,12,91.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M121.7,77V16.9h36.9v4.2c0,3.7-3,6.8-6.8,6.8h-18.4v13.5H150v3.5c0,4.1-3.3,7.5-7.5,7.5h-9.1v19.1 c0,3-2.5,5.5-5.5,5.5H121.7z"/>
|
||||
<path class="st0" d="M161.1,64.7c0-2,0.3-3.7,1-5.1c0.7-1.5,1.6-2.7,2.9-3.6c1.3-1,2.7-1.7,4.2-2.3c1.6-0.6,3.3-1,5.4-1.3l11.3-2 v-1.5c0-2-0.5-3.5-1.6-4.6c-1-1.1-2.6-1.6-4.5-1.6s-3.4,0.5-4.6,1.4c-1.2,1-1.8,2.2-1.8,3.8h-10.8c0.3-4.5,1.9-8.2,5.1-11 c3.1-2.8,7.2-4.3,12.3-4.3c5.3,0,9.5,1.3,12.6,4s4.7,6.6,4.7,11.8V77h-4.7c-2.8,0-5.1-2.1-5.5-4.8l-0.1-1.1 c-2.7,4.6-6.9,6.8-12.4,6.8c-3.9,0-7.1-1.2-9.6-3.6C162.4,72,161.1,68.8,161.1,64.7z M172.3,64c0,1.2,0.4,2.1,1.3,2.8 c0.9,0.7,2.1,1,3.7,1c1.4,0,2.7-0.3,3.9-0.9c1.2-0.6,2.2-1.5,3-2.7c1-1.4,1.5-3.2,1.5-5.3v-1.2l-8.7,1.8c-1.6,0.3-2.8,0.8-3.6,1.5 C172.7,61.8,172.3,62.7,172.3,64z"/>
|
||||
<path class="st0" d="M207,20.9c0-1.8,0.7-3.6,2-4.9c1.3-1.2,2.8-1.9,4.6-1.9c1.8,0,3.6,0.6,4.9,1.9c1.4,1.3,2.1,2.9,2.1,4.8 s-0.7,3.4-2,4.7c-1.3,1.3-2.9,1.9-4.8,1.9s-3.5-0.6-4.8-1.9C207.7,24.2,207.1,22.7,207,20.9z M208.2,77V33.5h11.2v38 c0,3-2.5,5.5-5.5,5.5H208.2z"/>
|
||||
<path class="st0" d="M230.4,77V33.5h9.6l1.1,6.8c0.8-2.1,2.3-3.9,4.4-5.2c2.1-1.4,4.9-2.1,8.3-2.1v11c-3.5,0-6.4,0.9-8.6,2.6 s-3.4,4.4-3.5,8.1v16.7c0,3-2.5,5.5-5.5,5.5L230.4,77L230.4,77z"/>
|
||||
<path class="st0" d="M259.6,33.5h11.9l6.6,26.1l0.8,4.6l1-4.6l7.4-26.1h9.9l7.4,26.1l0.9,4.6l0.8-4.6l6.7-26.1h11.9L313,72.9 c-0.7,2.4-3,4.1-5.5,4.1H300l-7.9-25.6L285,73c-0.8,2.3-3,3.9-5.4,3.9h-7L259.6,33.5z"/>
|
||||
<path class="st0" d="M330.5,20.7c0-1.8,0.7-3.4,2-4.7c1.3-1.3,2.9-1.9,4.8-1.9c1.8,0,3.4,0.6,4.8,1.9c1.3,1.3,2,2.8,2,4.7 c0,1.9-0.7,3.4-2,4.7c-1.3,1.3-2.9,1.9-4.8,1.9s-3.5-0.6-4.8-1.9C331.2,24.2,330.5,22.6,330.5,20.7z M331.7,77V33.5h11.2v38 c0,3-2.5,5.5-5.5,5.5H331.7z"/>
|
||||
<path class="st0" d="M354.8,77V33.5h9.6l0.9,5.8c1.1-2,2.6-3.6,4.6-4.9c2-1.2,4.4-1.9,7.2-1.9c4.5,0,8,1.4,10.4,4.3 s3.6,6.8,3.6,11.9v22.5c0,3.2-2.6,5.7-5.7,5.7h-5.5V51.4c0-2.5-0.5-4.5-1.6-5.8c-1-1.3-2.6-2-4.6-2c-2.3,0-4.1,0.9-5.5,2.7 c-1.4,1.8-2.2,4.4-2.2,7.9v17.1c0,3.2-2.6,5.7-5.7,5.7L354.8,77L354.8,77z"/>
|
||||
<path class="st0" d="M399.1,55.2c0-6.4,1.9-11.8,5.7-16.1c3.8-4.3,8.7-6.5,14.5-6.5c2.9,0,5.5,0.5,7.8,1.6s4,2.4,5.2,4.1V14.4 h11.2V77h-4.8c-2.7,0-5-2-5.4-4.7l-0.2-1.2c-3.1,4.5-7.7,6.8-13.9,6.8c-3.8,0-7.3-1-10.4-3s-5.5-4.7-7.2-8.2 C399.9,63.3,399.1,59.4,399.1,55.2z M410.5,55.2c0,3.7,1,6.6,3.1,8.9c2.1,2.3,4.7,3.4,7.8,3.4c2.9,0,5.5-1.1,7.7-3.2 c2.2-2.2,3.3-5.1,3.3-8.8V55c0-2.5-0.6-4.6-1.7-6.5s-2.5-3.2-4.1-4.1s-3.4-1.3-5.2-1.3c-3.1,0-5.7,1.1-7.8,3.4 S410.5,51.6,410.5,55.2z"/>
|
||||
<path class="st0" d="M452.2,63.8h6.9c2,0,3.7,1.2,4.8,2.9c0.2,0.4,0.6,0.7,0.9,1c1.1,0.9,2.6,1.4,4.5,1.4c1.7,0,3-0.4,4-1.1 c0.9-0.7,1.4-1.8,1.4-3c0-1.4-0.5-2.5-1.6-3.3s-3.2-1.5-6.2-2.1c-4.8-0.8-8.3-2.3-10.5-4.4c-2.3-2.1-3.4-4.9-3.4-8.5 c0-4,1.4-7.4,4.2-10.1c2.8-2.7,6.8-4.1,11.9-4.1c4.6,0,8.4,1.3,11.3,3.8c2.9,2.5,4.5,5.8,4.7,9.9H474c-0.1-3.3-1.7-5-5-5 c-1.5,0-2.7,0.4-3.5,1.2c-0.8,0.8-1.3,1.8-1.3,3.1c0,1.4,0.5,2.4,1.6,3.1s3.1,1.3,6,1.8c5.1,0.9,8.8,2.4,10.9,4.5 c2.2,2.1,3.2,5,3.2,8.7c0,2.4-0.4,4.5-1.3,6.4c-0.9,1.8-2.1,3.3-3.7,4.4c-1.6,1.1-3.3,2-5.3,2.5c-2,0.6-4.1,0.8-6.5,0.8 c-5.3,0-9.4-1.3-12.3-3.8C453.9,71.6,452.3,68.2,452.2,63.8z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is generated from FairwindsOps/documentation-template
|
||||
* DO NOT EDIT MANUALLY
|
||||
*/
|
||||
|
||||
var llcookieless = true;
|
||||
var sf14gv = 32793;
|
||||
(function() {
|
||||
var sf14g = document.createElement('script');
|
||||
sf14g.src = 'https://lltrck.com/lt-v2.min.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(sf14g, s);
|
||||
})();
|
||||
|
||||
!function(f,b,e,v,n,t,s)
|
||||
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
|
||||
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
|
||||
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
|
||||
n.queue=[];t=b.createElement(e);t.async=!0;
|
||||
t.src=v;s=b.getElementsByTagName(e)[0];
|
||||
s.parentNode.insertBefore(t,s)}(window,document,'script',
|
||||
'https://connect.facebook.net/en_US/fbevents.js');
|
||||
fbq('init', '521127644762074');
|
||||
fbq('track', 'PageView');
|
||||
|
||||
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||
})(window,document,'script','dataLayer','GTM-TM95WXQ');
|
||||