月度归档:2020年11月

Kubernetes 最佳安全实践指南


2020年11月27日 23:09:50   1,922 次浏览

对于大部分 Kubernetes 用户来说,安全是无关紧要的,或者说没那么紧要,就算考虑到了,也只是敷衍一下,草草了事。实际上 Kubernetes 提供了非常多的选项可以大大提高应用的安全性,只要用好了这些选项,就可以将绝大部分的攻击抵挡在门外。为了更容易上手,我将它们总结成了几个最佳实践配置,大家看完了就可以开干了。当然,本文所述的最佳安全实践仅限于 Pod 层面,也就是容器层面,于容器的生命周期相关,至于容器之外的安全配置(比如操作系统啦、k8s 组件啦),以后有机会再唠。

1. 为容器配置 Security Context

大部分情况下容器不需要太多的权限,我们可以通过 Security Context 限定容器的权限和访问控制,只需加上 SecurityContext 字段:

apiVersion: v1
kind: Pod
metadata:
  name: <Pod name>
spec:
  containers:
  - name: <container name>
  image: <image>
+   securityContext:

2. 禁用 allowPrivilegeEscalation

allowPrivilegeEscalation=true 表示容器的任何子进程都可以获得比父进程更多的权限。最好将其设置为 false,以确保 RunAsUser 命令不能绕过其现有的权限集。

apiVersion: v1
kind: Pod
metadata:
  name: <Pod name>
spec:
  containers:
  - name: <container name>
  image: <image>
    securityContext:
  +   allowPrivilegeEscalation: false

3. 不要使用 root 用户

为了防止来自容器内的提权攻击,最好不要使用 root 用户运行容器内的应用。UID 设置大一点,尽量大于 3000

apiVersion: v1
kind: Pod
metadata:
  name: <name>
spec:
  securityContext:
+   runAsUser: <UID higher than 1000>
+   runAsGroup: <UID higher than 3000>

4. 限制 CPU 和内存资源

这个就不用多说了吧,requests 和 limits 都加上。

5. 不必挂载 Service Account Token

ServiceAccount 为 Pod 中运行的进程提供身份标识,怎么标识呢?当然是通过 Token 啦,有了 Token,就防止假冒伪劣进程。如果你的应用不需要这个身份标识,可以不必挂载:

apiVersion: v1
kind: Pod
metadata:
  name: <name>
spec:
+ automountServiceAccountToken: false

6. 确保 seccomp 设置正确

对于 Linux 来说,用户层一切资源相关操作都需要通过系统调用来完成,那么只要对系统调用进行某种操作,用户层的程序就翻不起什么风浪,即使是恶意程序也就只能在自己进程内存空间那一分田地晃悠,进程一终止它也如风消散了。seccomp(secure computing mode)就是一种限制系统调用的安全机制,可以可以指定允许那些系统调用。

对于 Kubernetes 来说,大多数容器运行时都提供一组允许或不允许的默认系统调用。通过使用 runtime/default 注释或将 Pod 或容器的安全上下文中的 seccomp 类型设置为 RuntimeDefault,可以轻松地在 Kubernetes 中应用默认值。

apiVersion: v1
kind: Pod
metadata:
  name: <name>
  annotations:
  + seccomp.security.alpha.kubernetes.io/pod: "runtime/default"

7. 限制容器的 capabilities

容器依赖于传统的 Unix 安全模型,通过控制资源所属用户和组的权限,来达到对资源的权限控制。以 root 身份运行的容器拥有的权限远远超过其工作负载的要求,一旦发生泄露,攻击者可以利用这些权限进一步对网络进行攻击。

默认情况下,使用 Docker 作为容器运行时,会启用 NET_RAW capability,这可能会被恶意攻击者进行滥用。因此,建议至少定义一个PodSecurityPolicy(PSP),以防止具有 NET_RAW 功能的容器启动。

通过限制容器的 capabilities,可以确保受攻击的容器无法为攻击者提供横向攻击的有效路径,从而缩小攻击范围。

apiVersion: v1
kind: Pod
metadata:
  name: <name>
spec:
  securityContext:
  + runAsNonRoot: true
  + runAsUser: <specific user>
  capabilities:
  drop:
  + -NET_RAW
  + -ALL

8. 只读

如果容器不需要对根文件系统进行写入操作,最好以只读方式加载容器的根文件系统,可以进一步限制攻击者的手脚。

apiVersion: v1
kind: Pod
metadata:
  name: <Pod name>
spec:
  containers:
  - name: <container name>
  image: <image>
  securityContext:
  + readOnlyRootFilesystem: true

9 总结

总之,Kubernetes 提供了非常多的选项来增强集群的安全性,没有一个放之四海而皆准的解决方案,所以需要对这些选项非常熟悉,以及了解它们是如何增强应用程序的安全性,才能使集群更加稳定安全。

最后,请记住:你需要万分小心你的 YAML 文件内容缩进,如果你的 YAML 文件非常多,眼睛看不过来,希望下面的神器可以助你一臂之力:


Zabbix使用Python检查Haproxy状态页面


2020年11月26日 13:01:59   1,904 次浏览

概述

网上有很多使用zabbix监控haproxy的脚本,但大多数都使用的socket方式,而haproxy的stats页面页面我们经常需要访问的,所以我们这次使用python来抓取haproxy的stats页面。

haproxy的stats页面分析

<tr class="active0"><td class=ac><a name="app_push/push496">

当backend正常时,会显示绿色.

<tr class="active4"><td class=ac><a name="app_push/push096">

中间会有黄色的情况,backend反复故障恢复时会产生。 Python脚本抓取

#!/usr/bin/env python
#coding=utf-8
#Debug in Python2.7
import urllib2
import sys
import re
url = sys.argv[1]
#url = 'http://10.100.18.78:8888/status'
try:
    response = urllib2.urlopen(url,timeout=5).read();
except:
    print 'error to connect haproxy.'
    sys.exit(0)
pattern = re.compile('<tr class="active0"><td class=ac><a name="(.*?)"></a>')
items = re.findall(pattern, response)
data = []
for item in items:
    #print item
    data.append(item)
if len(data):
    print data
else:
    print 'ok'

当haproxy有backend故障时,会打印故障服务器,没有故障时显示OK,服务器无法连接,显示’error to connect haproxy.’ 故障显示如下

['app_push/push496', 'app_push/push092']

Zabbix中添加监控项 需要zabbix客户端自定义一个key来关联检查脚本。然后zabbix服务器端设置模板。这里我是用的字符串匹配。

#!/usr/bin/env python
from dingding import message
import requests
import sys
import re
import time
while True:
    time.sleep(30)
    url = 'http://10.28.xx.xx:65010/haproxy'
    try:
        response = requests.get(url=url, timeout=5).text

    except:
        print('error to connect haproxy.')
        sys.exit(0)
    pattern = re.compile('<tr class="active0"><td class=ac><a name="(.*?)"></a>')
    items = re.findall(pattern, response)
    data = []

    for item in items:
        #print item

        data.append(item)
    if len(data):
        print(data)
        message(text=data)
    else:
        print('ok')
dingding.py

#!/usr/bin/env python
#-*- coding: utf-8 -*-

'''
@Author: 风哥
@Email:  gujiwork@outlook.com
@Create Time: 2019/9/4
'''

import json
import requests


def message(text):
    # 告警通知
    headers = {
        'Content-Type': 'application/json;charset=utf-8',
    }

    alarm_user = 'phone1,phone2'
    notice_url = 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

    at_user = (alarm_user).split(',')
    json_text = {
        "msgtype": "text",
        "at": {
            "atMobiles":
                at_user,
            "isAtAll": False  # 为True表示@所有人
        },

        "text": {
            "content": (text)

        }
    }
    try:

        notice = requests.post(notice_url, json.dumps(json_text), headers=headers).content
        print(json.loads(notice))

    except BaseException as e:
        at_user = []
        print(e)

 

vue返回上一页


2020年11月26日 13:01:21   1,373 次浏览
如何使用点击方式控制当前页返回到上一个路由页面:
查阅相关资料,返回上一目录用到的是 this.$router.go(-1); 将该方法些到返回按钮上,点击触发该方法;
具体代码如下:
1.在当前页面添加返回按钮
<!--返回按钮--> 
<div class="backTo" v-show="isShow"> 
    <span v-on:click="back">返回</span> 
</div>
2.在方法体内现价back方法
methods:{ 
  back(){ 
    this.$router.go(-1);
    //返回上一层 
  }, 
},
问题2:如何控制”返回键” 的显示和隐藏: 由于这里需要频繁的改变”返回键“的显示和隐藏,所以这里考虑用v-show
data() { 
  return { 
    isShow:false 
  } 
}
触发isShow 的值改变的事件应该是当前页面路由地址的改变,并且这里需要使用watch完成监控:
watch:{ 
  $route(now,old){ 
  //监控路由变换,控制返回按钮的显示 
  if(now.path=="/home/home"){ 
    this.isShow=false; 
  } else{ 
    this.isShow=true; 
    } 
  } 
}
这样,当页面处在主页下的时候,返回键自动隐藏掉,如果不是当前主页,就显示返回键
第二种方式:vue2.0返回上一页
@click="$router.back(-1)"

 

页面: