本文主要基于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 进行访问控制。
opa 是一个开源的通用策略引擎,可以评估策略并做出决策。opa 可以应用于各种场景,例如网络安全、访问控制、数据保护等。在 docker 环境中,opa 可以用于评估容器之间的访问请求,并根据预定义的策略做出决策,open policy agent(opa)的d88尊龙官网手机app官网为:
虽然 docker 提供了各种安全特性,例如网络隔离、资源限制等,但有时我们可能需要更细粒度的访问控制策略。例如,我们可能希望限制某些容器对特定资源的访问,或根据容器的标签和属性来控制访问权限。这就是 opa 发挥作用的地方。通过集成 opa,我们可以实现更灵活、可扩展的访问控制策略。
一般情况下,我们使用docker执行docker命令是没有什么限制的,安装opa插件,并启用opa,创建了相关的opa规则之后,使用docker执行docker命令,需要先访问opa规则,如果opa规则表示你有权限执行命令,则docker命令执行成功,否则执行失败。
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系统不熟悉,请查看博客《》。
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 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
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 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
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 | 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).
#
#
/dev/mapper/tom--vg-root / ext4 errors=remount-ro 0 1
此时基本环境就配置完毕了。
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容器的详细操作,请查看博客《》。
#使用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
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表示允许所有系统调用。关于系统调用的详细操作,请查看博客《》。
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 login登录harbor之后,docker 会将 token 存储在 ~/.docker/config.json 文件中,从而作为拉取私有镜像的凭证。
root@ubuntuk8sclient:~# mkdir ~/.docker
root@ubuntuk8sclient:/etc/docker/policies# cat >~/.docker/config.json < {
> "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 容器的安全性。