docker使用Open Policy Agent(OPA)進行訪問控制

人生的哲理發表於2024-06-05

目錄
  • 一.系統環境
  • 二.前言
  • 三.Open Policy Agent 簡介
  • 四.Rego 語言簡介
  • 五.配置基本環境
  • 六.docker安裝OPA外掛
    • 6.1 安裝docker
    • 6.2 docker安裝OPA外掛
    • 6.3 啟用OPA
  • 七.OPA規則
    • 7.1 允許docker所有操作
    • 7.2 禁止docker所有操作
    • 7.3 禁止建立允許所有系統呼叫的docker容器
    • 7.4 根據Authz-User判斷使用者是否具有建立pod許可權
  • 八.總結

一.系統環境

本文主要基於Docker version 20.10.16和Linux作業系統Ubuntu 18.04。

伺服器版本 docker軟體版本 CPU架構
Ubuntu 18.04.5 LTS Docker version 20.10.16 x86_64

二.前言

在容器化技術中,Docker 已經成為廣泛使用的工具。然而,隨著容器數量的增加,確保容器之間的安全隔離變得越來越重要。Docker 提供了各種安全特性,但有時我們可能需要更細粒度的訪問控制策略。Open Policy Agent(OPA)是一個開源的通用策略引擎,可以與 Docker 整合,以實現更靈活的訪問控制。本文將介紹如何在 Docker 中使用 OPA 進行訪問控制。

三.Open Policy Agent 簡介

OPA 是一個開源的通用策略引擎,可以評估策略並做出決策。OPA 可以應用於各種場景,例如網路安全、訪問控制、資料保護等。在 Docker 環境中,OPA 可以用於評估容器之間的訪問請求,並根據預定義的策略做出決策,Open Policy Agent(OPA)的官網為:https://www.openpolicyagent.org/。

雖然 Docker 提供了各種安全特性,例如網路隔離、資源限制等,但有時我們可能需要更細粒度的訪問控制策略。例如,我們可能希望限制某些容器對特定資源的訪問,或根據容器的標籤和屬性來控制訪問許可權。這就是 OPA 發揮作用的地方。透過整合 OPA,我們可以實現更靈活、可擴充套件的訪問控制策略。

一般情況下,我們使用docker執行docker命令是沒有什麼限制的,安裝OPA外掛,並啟用OPA,建立了相關的OPA規則之後,使用docker執行docker命令,需要先訪問OPA規則,如果OPA規則表示你有許可權執行命令,則docker命令執行成功,否則執行失敗。

四.Rego 語言簡介

Rego 是一種用於編寫策略的語言,是 OPA 的核心組成部分。它是一種宣告性語言,可以描述複雜的資料結構和邏輯。Rego 語法簡潔,易於理解,使得編寫策略變得更加簡單。在本文中,我們將使用 Rego 語言編寫訪問控制策略。

五.配置基本環境

本次使用一臺新的Ubuntu機器(使用別的系統也行),下面給新機器配置基本環境。

檢視Ubuntu系統版本。

root@localhost:~# lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.5 LTS
Release:	18.04
Codename:	bionic

首先設定主機名。

root@localhost:~# vim /etc/hostname 

root@localhost:~# cat /etc/hostname
ubuntuk8sclient

配置節點靜態IP地址(可選)。如果您對Ubuntu系統不熟悉,請檢視部落格《centos系統和Ubuntu系統命令區別以及常見操作》。

root@localhost:~# vim /etc/netplan/01-netcfg.yaml

root@localhost:~# cat /etc/netplan/01-netcfg.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    ens32:
      dhcp4: no
      addresses: [192.168.110.139/24]
      gateway4: 192.168.110.2
      nameservers:
        addresses: [192.168.110.2,114.114.114.114]

使網路卡配置生效。

root@localhost:~# netplan apply 

測試機器是否可以訪問網路。

root@localhost:~# ping www.baidu.com
PING www.baidu.com (14.215.177.39) 56(84) bytes of data.
64 bytes from www.baidu.com (14.215.177.39): icmp_seq=1 ttl=128 time=54.3 ms
64 bytes from www.baidu.com (14.215.177.39): icmp_seq=2 ttl=128 time=44.6 ms
64 bytes from www.baidu.com (14.215.177.39): icmp_seq=3 ttl=128 time=41.3 ms
64 bytes from www.baidu.com (14.215.177.39): icmp_seq=4 ttl=128 time=37.0 ms
64 bytes from www.baidu.com (14.215.177.39): icmp_seq=5 ttl=128 time=43.7 ms
^C
--- www.baidu.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4007ms
rtt min/avg/max/mdev = 37.072/44.239/54.332/5.695 ms

檢視IP。

root@localhost:~# ifconfig
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.110.139  netmask 255.255.255.0  broadcast 192.168.110.255
        inet6 fe80::20c:29ff:fe97:b27b  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:97:b2:7b  txqueuelen 1000  (Ethernet)
        RX packets 20269  bytes 22473377 (22.4 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 7755  bytes 544420 (544.4 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 1650  bytes 119324 (119.3 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1650  bytes 119324 (119.3 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

配置IP和主機名對映。

root@localhost:~# vim /etc/hosts

root@localhost:~# cat /etc/hosts
127.0.0.1	localhost
127.0.1.1	tom
192.168.110.139 ubuntuk8sclient

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

配置軟體源。

root@ubuntuk8sclient:~# vim /etc/apt/sources.list

 #軟體源如下,最後三行是k8s源
root@ubuntuk8sclient:~# cat /etc/apt/sources.list
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse

deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu bionic stable
# deb-src [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu bionic stable

apt-key.gpg是k8s的deb源公鑰,載入k8s的deb源公鑰命令為:apt-key add apt-key.gpg。

下載並載入k8s的deb源公鑰命令為:curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - ; apt-get update,但是谷歌的網址訪問不了,我們直接去網上下載apt-key.gpg檔案。

root@ubuntuk8sclient:~# ls
apt-key.gpg  

載入k8s的deb源公鑰。

root@ubuntuk8sclient:~# cat apt-key.gpg | apt-key add -
OK

更新軟體源。

root@ubuntuk8sclient:~# apt-get update

關閉防火牆。

root@ubuntuk8sclient:~# ufw disable
Firewall stopped and disabled on system startup

Linux swapoff命令用於關閉系統交換分割槽(swap area)。如果不關閉swap,就會在kubeadm初始化Kubernetes的時候報錯:“[ERROR Swap]: running with swap on is not supported. Please disable swap”。

root@ubuntuk8sclient:~# swapoff -a ;sed -i '/swap/d' /etc/fstab

root@ubuntuk8sclient:~# cat /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
/dev/mapper/tom--vg-root /               ext4    errors=remount-ro 0       1

此時基本環境就配置完畢了。

六.docker安裝OPA外掛

6.1 安裝docker

安裝docker。

root@ubuntuk8sclient:~# apt-get install docker-ce -y

root@ubuntuk8sclient:~# which docker
/usr/bin/docker

檢視docker安裝包。

root@ubuntuk8sclient:~# dpkg -l | grep docker
ii  docker-ce                              5:20.10.16~3-0~ubuntu-bionic                    amd64        Docker: the open-source application container engine
ii  docker-ce-cli                          5:20.10.16~3-0~ubuntu-bionic                    amd64        Docker CLI: the open-source application container engine
ii  docker-ce-rootless-extras              5:20.10.16~3-0~ubuntu-bionic                    amd64        Rootless support for Docker.
ii  docker-scan-plugin                     0.17.0~ubuntu-bionic                            amd64        Docker scan cli plugin.

設定docker開機自啟動並現在啟動docker。

root@ubuntuk8sclient:~# systemctl enable docker --now
Synchronizing state of docker.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable docker

檢視docker狀態。

root@ubuntuk8sclient:~# systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2022-05-27 17:39:41 CST; 2min 27s ago
     Docs: https://docs.docker.com
 Main PID: 2574 (dockerd)
    Tasks: 8
   CGroup: /system.slice/docker.service
           └─2574 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

May 27 17:39:37 ubuntuk8sclient dockerd[2574]: time="2022-05-27T17:39:37.223612352+08:00" level=info msg="ClientConn switching balancer to \"pick_first\"" module=grpc
May 27 17:39:37 ubuntuk8sclient dockerd[2574]: time="2022-05-27T17:39:37.512415652+08:00" level=warning msg="Your kernel does not support swap memory limit"
May 27 17:39:37 ubuntuk8sclient dockerd[2574]: time="2022-05-27T17:39:37.512456896+08:00" level=warning msg="Your kernel does not support CPU realtime scheduler"
May 27 17:39:37 ubuntuk8sclient dockerd[2574]: time="2022-05-27T17:39:37.512593678+08:00" level=info msg="Loading containers: start."
May 27 17:39:40 ubuntuk8sclient dockerd[2574]: time="2022-05-27T17:39:40.261550128+08:00" level=info msg="Default bridge (docker0) is assigned with an IP address 172.17.0.0/16. Daemon option --bip can be used t

檢視docker版本。

root@ubuntuk8sclient:~# docker --version
Docker version 20.10.16, build aa7e414

配置docker阿里雲映象加速器。

root@ubuntuk8sclient:~# vim /etc/docker/daemon.json

root@ubuntuk8sclient:~# cat /etc/docker/daemon.json
{
        "registry-mirrors": ["https://frz7i079.mirror.aliyuncs.com"]
}

重新載入配置檔案,重啟docker。

root@ubuntuk8sclient:~# systemctl daemon-reload ; systemctl restart docker

root@ubuntuk8sclient:~# systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2022-05-27 17:45:41 CST; 5s ago
     Docs: https://docs.docker.com
 Main PID: 4330 (dockerd)
    Tasks: 8
   CGroup: /system.slice/docker.service
           └─4330 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

下載一個nginx映象。

root@ubuntuk8sclient:~# docker pull nginx

root@ubuntuk8sclient:~# docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
nginx        latest    605c77e624dd   4 months ago   141MB

現在建立docker容器是沒有限制的,可以自由建立和刪除。關於docker容器的詳細操作,請檢視部落格《一文搞懂docker容器基礎:docker映象管理,docker容器管理》。

#使用nginx映象建立容器
root@ubuntuk8sclient:~# docker run -dit --name=nginxweb --restart=always nginx
16d5558fbe8d8956d61714326bea89e5a86424503c323dab03e729927f71fb5b

#檢視容器
root@ubuntuk8sclient:~# docker ps 
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
16d5558fbe8d   nginx     "/docker-entrypoint.…"   16 seconds ago   Up 13 seconds   80/tcp    nginxweb

#刪除容器
root@ubuntuk8sclient:~# docker rm -f nginxweb 
nginxweb

root@ubuntuk8sclient:~# docker ps 
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

6.2 docker安裝OPA外掛

在安裝OPA外掛之前,先介紹下docker外掛常用命令,Docker外掛是增強Docker引擎功能的程序外擴充套件。docker plugin命令用於管理外掛。

docker plugin create     #從rootfs和配置建立一個外掛。外掛資料目錄必須包含config.json和rootfs目錄。
docker plugin disable    #禁用外掛
docker plugin enable     #啟用外掛
docker plugin inspect    #顯示一個或多個外掛的詳細資訊
docker plugin install    #安裝一個外掛
docker plugin ls         #列出所有外掛
docker plugin push       #將外掛推送到登錄檔
docker plugin rm         #刪除一個或多個外掛
docker plugin set        #更改外掛的設定
docker plugin upgrade    #升級現有外掛

/etc/docker/policies用來存放opa規則。

root@ubuntuk8sclient:~# mkdir -p /etc/docker/policies

root@ubuntuk8sclient:~# ls /etc/docker/
daemon.json  key.json  policies

檢視docker外掛,現在沒有任何外掛。

root@ubuntuk8sclient:~# docker plugin list
ID        NAME      DESCRIPTION   ENABLED

下載好的docker外掛會放在/var/lib/docker/plugins/目錄。

root@ubuntuk8sclient:~# ls /var/lib/docker/plugins/
storage  tmp

安裝OPA外掛。

root@ubuntuk8sclient:~# docker plugin install openpolicyagent/opa-docker-authz-v2:0.8 opa-args="-policy-file /opa/policies/authz.rego"
Plugin "openpolicyagent/opa-docker-authz-v2:0.8" is requesting the following privileges:
 - network: [host]
 - mount: [/etc/docker]
Do you grant the above permissions? [y/N] y
0.8: Pulling from openpolicyagent/opa-docker-authz-v2
Digest: sha256:2fbbef244625e57f2beb7967a1b21c43ce5c7e6ec823fb1c35fe1b327ae3a1c4
cb581d64bd7f: Complete 
Installed plugin openpolicyagent/opa-docker-authz-v2:0.8

現在OPA外掛就安裝好了。

root@ubuntuk8sclient:~# docker plugin list
ID             NAME                                      DESCRIPTION                                     ENABLED
20b4566c59fc   openpolicyagent/opa-docker-authz-v2:0.8   A policy-enabled authorization plugin for Do…   true

docker OPA外掛安裝好之後,在/var/lib/docker/plugins/目錄下。

root@ubuntuk8sclient:~# ls /var/lib/docker/plugins/
20b4566c59fc71641bda21da72d75299405e9c5c8b4cc859f6ab636f4f19cc52  storage  tmp

檢視OPA屬性。

注意:"-policy-file /opa/policies/authz.rego"裡的/opa不是作業系統裡的/opa目錄,而是/etc/docker/下的opa。

docker plugin inspect 20b4566c59fc顯示的Mounts選項可以看出,/etc/docker目錄掛載到/opa目錄了,所以訪問容器/opa目錄就相當於訪問宿主機/etc/docker目錄。

root@ubuntuk8sclient:~# docker plugin inspect 20b4566c59fc
[
    {
        "Config": {
            ......
            #注意:"-policy-file /opa/policies/authz.rego"裡的/opa不是作業系統裡的/opa目錄,而是/etc/docker/下的opa,
            #docker plugin inspect 20b4566c59fc顯示的Mounts選項可以看出,/etc/docker目錄掛載到/opa目錄了,所以訪問容器/opa目錄就相當於訪問宿主機/etc/docker目錄
            "Mounts": [
                {
                    "Description": "",
                    "Destination": "/opa",
                    "Name": "policy",
                    "Options": [
                        "bind",
                        "ro"
                    ],
                    "Settable": [
                        "source"
                    ],
                    "Source": "/etc/docker",
                    "Type": "none"
                }
            ],
           ......
            "Mounts": [
                {
                    "Description": "",
                    "Destination": "/opa",
                    "Name": "policy",
                    "Options": [
                        "bind",
                        "ro"
                    ],
                    "Settable": [
                        "source"
                    ],
                    "Source": "/etc/docker",
                    "Type": "none"
                }
            ]
        }
    }
]

6.3 啟用OPA

安裝OPA外掛之後需要啟用OPA,"authorization-plugins": ["openpolicyagent/opa-docker-authz-v2:0.8"]指定OPA外掛。

root@ubuntuk8sclient:~# cd /etc/docker/policies/

root@ubuntuk8sclient:/etc/docker/policies# vim /etc/docker/daemon.json 

root@ubuntuk8sclient:/etc/docker/policies# cat /etc/docker/daemon.json
{
        "registry-mirrors": ["https://frz7i079.mirror.aliyuncs.com"],
        "authorization-plugins": ["openpolicyagent/opa-docker-authz-v2:0.8"]
}

重啟docker,這樣就啟用了OPA。

root@ubuntuk8sclient:/etc/docker/policies# systemctl daemon-reload ; systemctl restart docker

七.OPA規則

7.1 允許docker所有操作

下面開始編寫OPA規則,OPA規則使用rego語言編寫,allow := true 表示允許所有操作。

root@ubuntuk8sclient:/etc/docker/policies# vim authz.rego

root@ubuntuk8sclient:/etc/docker/policies# cat /etc/docker/policies/authz.rego 
package docker.authz
allow := true

可以檢視映象及其所有操作。

root@ubuntuk8sclient:/etc/docker/policies# docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
nginx        latest    605c77e624dd   5 months ago   141MB

7.2 禁止docker所有操作

編輯OPA規則,allow := false表示禁止所有操作。

root@ubuntuk8sclient:/etc/docker/policies# vim /etc/docker/policies/authz.rego

root@ubuntuk8sclient:/etc/docker/policies# cat /etc/docker/policies/authz.rego
package docker.authz
allow := false

現在docker的所有操作都執行不了了。

root@ubuntuk8sclient:/etc/docker/policies# docker images
Error response from daemon: authorization denied by plugin openpolicyagent/opa-docker-authz-v2:0.8: request rejected by administrative policy

root@ubuntuk8sclient:/etc/docker/policies# docker ps
Error response from daemon: authorization denied by plugin openpolicyagent/opa-docker-authz-v2:0.8: request rejected by administrative policy

7.3 禁止建立允許所有系統呼叫的docker容器

OPA規則設定為允許所有docker請求。

root@ubuntuk8sclient:/etc/docker/policies# vim /etc/docker/policies/authz.rego

root@ubuntuk8sclient:/etc/docker/policies# cat /etc/docker/policies/authz.rego
package docker.authz
#allow := true允許所有docker請求
allow := true

使用nginx映象建立一個允許所有系統呼叫的容器,--security-opt seccomp:unconfined表示允許所有系統呼叫。關於系統呼叫的詳細操作,請檢視部落格《在kubernetes裡使用seccomp限制容器的系統呼叫》。

root@ubuntuk8sclient:/etc/docker/policies# docker run -dit --restart=always --name=nginxweb --security-opt seccomp:unconfined nginx
033a0e8e38c56a00400eeefe5424f55ca953e320e6d668831f4cdc580837294f

root@ubuntuk8sclient:/etc/docker/policies# docker ps 
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
033a0e8e38c5   nginx     "/docker-entrypoint.…"   5 seconds ago   Up 4 seconds   80/tcp    nginxweb

檢視nginxweb的屬性,在docker inspect nginxweb的輸出中,可以看到HostConfig.SecurityOpt[seccomp:unconfined],建立docker指定的選項都可以在docker inspect裡看到。

root@ubuntuk8sclient:/etc/docker/policies# docker inspect nginxweb
[
    {
        ......
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": [
                "seccomp:unconfined"
            ],
            "UTSMode": "",
              ......
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }
            }
        }
    }
]

刪除docker容器。

root@ubuntuk8sclient:/etc/docker/policies# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
033a0e8e38c5   nginx     "/docker-entrypoint.…"   6 minutes ago   Up 6 minutes   80/tcp    nginxweb

root@ubuntuk8sclient:/etc/docker/policies# docker rm -f nginxweb
nginxweb

root@ubuntuk8sclient:/etc/docker/policies# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

修改OPA規則,現在OPA規則HostConfig.SecurityOpt[_] == "seccomp:unconfined"都deny了,所以docker指定--security-opt seccomp:unconfined選項時,就執行不了了。

root@ubuntuk8sclient:/etc/docker/policies# vim /etc/docker/policies/authz.rego 

root@ubuntuk8sclient:/etc/docker/policies# cat /etc/docker/policies/authz.rego
package docker.authz
#預設拒絕
default allow = false

#allow這裡可以寫all,表示允許所有
#表示除了拒絕之外的那些都允許
allow {
    not deny
}

#表示拒絕seccomp_unconfined
deny {
    seccomp_unconfined
}

#seccomp_unconfined的詳細資訊
seccomp_unconfined {
    # This expression asserts that the string on the right-hand side is equal
    # to an element in the array SecurityOpt referenced on the left-hand side.
    input.Body.HostConfig.SecurityOpt[_] == "seccomp:unconfined"
}

現在允許所有系統呼叫的docker容器就建立不了了,備註:--security-opt seccomp:unconfined 表示允許所有的系統呼叫。

root@ubuntuk8sclient:/etc/docker/policies# docker run -dit --restart=always --name=nginxweb --security-opt seccomp:unconfined nginx
docker: Error response from daemon: authorization denied by plugin openpolicyagent/opa-docker-authz-v2:0.8: request rejected by administrative policy.
See 'docker run --help'.

建立普通的容器就可以成功。

root@ubuntuk8sclient:/etc/docker/policies# docker run -dit --restart=always --name=nginxweb nginx
304948d90988bbba4b7c0503980c60dfd636f2dccd33e90f2158fc93b6c7c63c

root@ubuntuk8sclient:/etc/docker/policies# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
304948d90988   nginx     "/docker-entrypoint.…"   4 seconds ago   Up 3 seconds   80/tcp    nginxweb

root@ubuntuk8sclient:/etc/docker/policies# docker rm -f nginxweb 
nginxweb

root@ubuntuk8sclient:/etc/docker/policies# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

7.4 根據Authz-User判斷使用者是否具有建立pod許可權

使用harbor搭建一個映象倉庫,映象倉庫裡新建專案,可以設定是否允許匿名使用者pull映象,如果設定了不允許匿名使用者pull映象,則客戶端必須docker login登入才行,否則docker pull拉取不了映象,docker push的話必須登入,不能匿名使用者push映象到映象倉庫。關於harbor映象倉庫的詳細操作,請檢視部落格《搭建docker映象倉庫(二):使用harbor搭建本地映象倉庫》。

當我們使用docker login登入harbor之後,Docker 會將 token 儲存在 ~/.docker/config.json 檔案中,從而作為拉取私有映象的憑證。

root@ubuntuk8sclient:~# mkdir ~/.docker

root@ubuntuk8sclient:/etc/docker/policies# cat >~/.docker/config.json <<EOF
> {
>     "HttpHeaders": {
>         "Authz-User": "alice"
>     }
> }
> EOF

config.json表示現在是alice登入拉取私有映象的。

root@ubuntuk8sclient:~# cat ~/.docker/config.json 
{
    "HttpHeaders": {
        "Authz-User": "alice"
    }
}

編輯OPA規則,如果使用者被授予讀寫許可權,則允許建立容器。

root@ubuntuk8sclient:~# vim /etc/docker/policies/authz.rego 

root@ubuntuk8sclient:~# cat /etc/docker/policies/authz.rego
package docker.authz
#預設拒絕
default allow = false

# allow if the user is granted read/write access.
#如果使用者被授予讀寫許可權,則允許
allow {
    user_id := input.Headers["Authz-User"]
    user := users[user_id]
    not user.readOnly
}

# allow if the user is granted read-only access and the request is a GET.
#如果使用者被授予只讀訪問許可權並且請求是GET,則允許
allow {
    user_id := input.Headers["Authz-User"]
    users[user_id].readOnly
    input.Method == "GET"
}

# users defines permissions for the user. In this case, we define a single
# attribute 'readOnly' that controls the kinds of commands the user can run.
#bob使用者只讀,alice使用者讀寫
users := {
    "bob": {"readOnly": true},
    "alice": {"readOnly": false},
}

現在是"Authz-User": "alice",alice具有讀寫許可權,成功建立容器。

root@ubuntuk8sclient:~# docker run -dit --restart=always --name=nginxweb nginx
e6aeb23a91a55fbad3fd5db9d0ac87ade1be13e990d17e6a29e9f0ca83cb5424

root@ubuntuk8sclient:~# docker ps 
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
e6aeb23a91a5   nginx     "/docker-entrypoint.…"   4 seconds ago   Up 3 seconds   80/tcp    nginxweb

root@ubuntuk8sclient:~# docker rm -f nginxweb 
nginxweb

表示現在是bob登入拉取私有映象的。

root@ubuntuk8sclient:~# vim ~/.docker/config.json

root@ubuntuk8sclient:~# cat ~/.docker/config.json
{
    "HttpHeaders": {
        "Authz-User": "bob"
    }
}

bob只有只讀許可權,並且只能執行get,建立容器失敗。

root@ubuntuk8sclient:~# docker run -dit --restart=always --name=nginxweb nginx
docker: Error response from daemon: authorization denied by plugin openpolicyagent/opa-docker-authz-v2:0.8: request rejected by administrative policy.
See 'docker run --help'.

八.總結

本文介紹瞭如何使用 Open Policy Agent(OPA)為 Docker 容器提供訪問控制。透過使用 OPA,我們可以輕鬆地實現細粒度的訪問控制策略,從而提高 Docker 容器的安全性。

相關文章