Clair是CoreOS提供的一款根据CVE的信息确认镜像各层安全状况的开源工具,harbor集成了clair到其功能之中,这也是和其他同类工具相比一个突出的亮点,而在其集成的实现中,首先clair的功能依然是靠其官方镜像和postgres结合形成,而扫描之后的信息则通过harbor自身的数据库进行保存。
在habor中集成clair的功能,方式非常简单,只需要在安装史指定with-clair选项即可
安装命令:sh install.sh –with-clair
而在harbor.cfg中与clair相关的设定信息如下:
设定项 | 说明 | 缺省值 |
---|---|---|
clair_db_host | clair数据库host,HA方式需要指定外部地址 | postgres |
clair_db_password | 数据库用户密码 | password |
clair_db_port | postgre服务端口 | 5432 |
clair_db | postgres数据库名 | postgres |
设定值使用如上缺省值,只是修改clair_db_password:password -> liumiaopw
[root@liumiao harbor]# grep clair_db_password harbor.cfg
clair_db_password = liumiaopw
[root@liumiao harbor]#
[root@liumiao harbor]# ./prepare
Clearing the configuration file: ./common/config/adminserver/env
Clearing the configuration file: ./common/config/ui/env
Clearing the configuration file: ./common/config/ui/app.conf
Clearing the configuration file: ./common/config/ui/private_key.pem
Clearing the configuration file: ./common/config/db/env
Clearing the configuration file: ./common/config/jobservice/env
Clearing the configuration file: ./common/config/jobservice/config.yml
Clearing the configuration file: ./common/config/registry/config.yml
Clearing the configuration file: ./common/config/registry/root.crt
Clearing the configuration file: ./common/config/nginx/cert/192.168.163.128.crt
Clearing the configuration file: ./common/config/nginx/cert/192.168.163.128.key
Clearing the configuration file: ./common/config/nginx/nginx.conf
Clearing the configuration file: ./common/config/log/logrotate.conf
loaded secret from file: /data/secretkey
Generated configuration file: ./common/config/nginx/nginx.conf
Generated configuration file: ./common/config/adminserver/env
Generated configuration file: ./common/config/ui/env
Generated configuration file: ./common/config/registry/config.yml
Generated configuration file: ./common/config/db/env
Generated configuration file: ./common/config/jobservice/env
Generated configuration file: ./common/config/jobservice/config.yml
Generated configuration file: ./common/config/log/logrotate.conf
Generated configuration file: ./common/config/jobservice/config.yml
Generated configuration file: ./common/config/ui/app.conf
Generated certificate, key file: ./common/config/ui/private_key.pem, cert file: ./common/config/registry/root.crt
The configuration files are ready, please use docker-compose to start the service.
[root@liumiao harbor]#
安装
[root@liumiao harbor]# sh install.sh --with-clair
[Step 0]: checking installation environment ...
Note: docker version: 1.13.1
Note: docker-compose version: 1.13.0
[Step 1]: loading Harbor images ...
Loaded image: vmware/registry-photon:v2.6.2-v1.5.2
Loaded image: vmware/photon:1.0
Loaded image: vmware/mariadb-photon:v1.5.2
Loaded image: vmware/harbor-log:v1.5.2
Loaded image: vmware/nginx-photon:v1.5.2
Loaded image: vmware/notary-signer-photon:v0.5.1-v1.5.2
Loaded image: vmware/postgresql-photon:v1.5.2
Loaded image: vmware/harbor-db:v1.5.2
Loaded image: vmware/harbor-jobservice:v1.5.2
Loaded image: vmware/clair-photon:v2.0.4-v1.5.2
Loaded image: vmware/harbor-adminserver:v1.5.2
Loaded image: vmware/harbor-ui:v1.5.2
Loaded image: vmware/redis-photon:v1.5.2
Loaded image: vmware/notary-server-photon:v0.5.1-v1.5.2
Loaded image: vmware/harbor-migrator:v1.5.0
[Step 2]: preparing environment ...
Clearing the configuration file: ./common/config/adminserver/env
Clearing the configuration file: ./common/config/ui/env
Clearing the configuration file: ./common/config/ui/app.conf
Clearing the configuration file: ./common/config/ui/private_key.pem
Clearing the configuration file: ./common/config/db/env
Clearing the configuration file: ./common/config/jobservice/env
Clearing the configuration file: ./common/config/jobservice/config.yml
Clearing the configuration file: ./common/config/registry/config.yml
Clearing the configuration file: ./common/config/registry/root.crt
Clearing the configuration file: ./common/config/nginx/cert/192.168.163.128.crt
Clearing the configuration file: ./common/config/nginx/cert/192.168.163.128.key
Clearing the configuration file: ./common/config/nginx/nginx.conf
Clearing the configuration file: ./common/config/log/logrotate.conf
loaded secret from file: /data/secretkey
Generated configuration file: ./common/config/nginx/nginx.conf
Generated configuration file: ./common/config/adminserver/env
Generated configuration file: ./common/config/ui/env
Generated configuration file: ./common/config/registry/config.yml
Generated configuration file: ./common/config/db/env
Generated configuration file: ./common/config/jobservice/env
Generated configuration file: ./common/config/jobservice/config.yml
Generated configuration file: ./common/config/log/logrotate.conf
Generated configuration file: ./common/config/jobservice/config.yml
Generated configuration file: ./common/config/ui/app.conf
Generated certificate, key file: ./common/config/ui/private_key.pem, cert file: ./common/config/registry/root.crt
Generated configuration file: ./common/config/clair/postgres_env
Generated configuration file: ./common/config/clair/config.yaml
Generated configuration file: ./common/config/clair/clair_env
The configuration files are ready, please use docker-compose to start the service.
[Step 3]: checking existing instance of Harbor ...
[Step 4]: starting Harbor ...
Creating network "harbor_harbor" with the default driver
Creating network "harbor_harbor-clair" with the default driver
Creating harbor-log ...
Creating harbor-log ... done
Creating harbor-adminserver ...
Creating registry ...
Creating clair-db ...
Creating harbor-db ...
Creating redis ...
Creating harbor-db
Creating harbor-adminserver
Creating clair-db
Creating registry
Creating redis ... done
Creating registry ... done
Creating clair
Creating harbor-ui ...
Creating harbor-ui ... done
Creating harbor-jobservice ...
Creating nginx ...
Creating harbor-jobservice
Creating nginx ... done
✔ ----Harbor has been installed and started successfully.----
Now you should be able to visit the admin portal at https://192.168.163.128:8848.
For more details, please visit https://github.com/vmware/harbor .
[root@liumiao harbor]#
结果确认
[root@liumiao harbor]# docker-compose -f docker-compose.clair.yml -f docker-compose.yml ps
Name Command State Ports
-------------------------------------------------------------------------------------------------------------------------------
clair /docker-entrypoint.sh Up 6060/tcp, 6061/tcp
clair-db /entrypoint.sh postgres Up 5432/tcp
harbor-adminserver /harbor/start.sh Up
harbor-db /usr/local/bin/docker-entr ... Up 3306/tcp
harbor-jobservice /harbor/start.sh Up
harbor-log /bin/sh -c /usr/local/bin/ ... Up 127.0.0.1:1514->10514/tcp
harbor-ui /harbor/start.sh Up
nginx nginx -g daemon off; Up 0.0.0.0:8848->443/tcp, 0.0.0.0:4443->4443/tcp, 0.0.0.0:80->80/tcp
redis docker-entrypoint.sh redis ... Up 6379/tcp
registry /entrypoint.sh serve /etc/ ... Up 5000/tcp
[root@liumiao harbor]#
[root@liumiao harbor]# docker login -uroot -pliumiaopw 192.168.163.128:8848
Error response from daemon: Get https://192.168.163.128:8848/v2/: unauthorized: authentication required
[root@liumiao harbor]#
[root@liumiao harbor]# docker login -uadmin -pliumiaopw 192.168.163.128:8848
Login Succeeded
[root@liumiao harbor]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
be8881be8156: Pull complete
32d9726baeef: Pull complete
87e5e6f71297: Pull complete
Digest: sha256:d85914d547a6c92faa39ce7058bd7529baacab7e0cd4255442b04577c4d1f424
Status: Downloaded newer image for nginx:latest
[root@liumiao harbor]# docker tag nginx 192.168.163.128:8848/library/nginx:latest
[root@liumiao harbor]# docker push 192.168.163.128:8848/library/nginx:latest
The push refers to a repository [192.168.163.128:8848/library/nginx]
08d25fa0442e: Pushed
a8c4aeeaa045: Pushed
cdb3f9544e4c: Pushed
latest: digest: sha256:2de9d5fc6585b3f330ff5f2c323d2a4006a49a476729bbc0910b695771526e3f size: 948
[root@liumiao harbor]#
前面提到admin是有权限进行镜像扫描的,通过UI可以看到刚刚推送的镜像还是Not Scanned的状态
选中并进行扫描可以看到当前最新的nginx镜像是没有严重CVE问题的
注意:clair的根本在于CVE的比对,所以自身的数据库数据的更新是非常重要的,就如同病毒库需要更新一样请同样注意clair本身的CVE数据相关的更新是否完成。
与clair扫描相关的数据库表主要有如下几个:
[root@liumiao harbor]# docker exec -it harbor-db sh
sh-4.3# mysql -uroot -pliumiaopw
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 57
Server version: 10.2.14-MariaDB Source distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> use registry
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [registry]> show tables;
+-------------------------------+
| Tables_in_registry |
+-------------------------------+
| access |
| access_log |
| alembic_version |
| clair_vuln_timestamp |
| harbor_label |
| harbor_resource_label |
| img_scan_job |
| img_scan_overview |
| project |
| project_member |
| project_metadata |
| properties |
| replication_immediate_trigger |
| replication_job |
| replication_policy |
| replication_target |
| repository |
| role |
| user |
| user_group |
+-------------------------------+
20 rows in set (0.00 sec)
MariaDB [registry]> desc clair_vuln_timestamp
-> ;
+-------------+--------------+------+-----+---------------------+-------------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------------------+-------------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| namespace | varchar(128) | NO | UNI | NULL | |
| last_update | timestamp | NO | | current_timestamp() | on update current_timestamp() |
+-------------+--------------+------+-----+---------------------+-------------------------------+
3 rows in set (0.00 sec)
MariaDB [registry]> desc img_scan_job
-> ;
+---------------+--------------+------+-----+---------------------+-------------------------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------------------+-------------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| status | varchar(64) | NO | MUL | NULL | |
| repository | varchar(256) | NO | MUL | NULL | |
| tag | varchar(128) | NO | | NULL | |
| digest | varchar(128) | YES | MUL | NULL | |
| job_uuid | varchar(64) | YES | MUL | NULL | |
| creation_time | timestamp | NO | | current_timestamp() | |
| update_time | timestamp | NO | | current_timestamp() | on update current_timestamp() |
+---------------+--------------+------+-----+---------------------+-------------------------------+
8 rows in set (0.00 sec)
MariaDB [registry]> desc img_scan_overview;
+---------------------+---------------+------+-----+---------------------+-------------------------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------------+------+-----+---------------------+-------------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| image_digest | varchar(128) | NO | UNI | NULL | |
| scan_job_id | int(11) | NO | | NULL | |
| severity | int(11) | NO | | 0 | |
| components_overview | varchar(2048) | YES | | NULL | |
| details_key | varchar(128) | YES | | NULL | |
| creation_time | timestamp | NO | | current_timestamp() | |
| update_time | timestamp | NO | | current_timestamp() | on update current_timestamp() |
+---------------------+---------------+------+-----+---------------------+-------------------------------+
8 rows in set (0.00 sec)
MariaDB [registry]>
扫描信息和执行结果
MariaDB [registry]> select * from img_scan_overview;
+----+-------------------------------------------------------------------------+-------------+----------+----------------------------------------------------+------------------------------------------------------------------+---------------------+---------------------+
| id | image_digest | scan_job_id | severity | components_overview | details_key | creation_time | update_time |
+----+-------------------------------------------------------------------------+-------------+----------+----------------------------------------------------+------------------------------------------------------------------+---------------------+---------------------+
| 1 | sha256:19fca0f4a812d0ba4ad89a4c345ce660ecc7c14c1ce9a9c12ac9db1ca62b4602 | 1 | 0 | | | 2018-08-19 00:00:21 | 2018-08-19 00:00:21 |
| 2 | sha256:2de9d5fc6585b3f330ff5f2c323d2a4006a49a476729bbc0910b695771526e3f | 2 | 1 | {"total":80,"summary":[{"severity":1,"count":80}]} | 6d33c67920b31f6dcea328762fe1a814de928a185d9397f61b15a278c17184f2 | 2018-08-19 03:16:33 | 2018-08-19 03:16:37 |
+----+-------------------------------------------------------------------------+-------------+----------+----------------------------------------------------+------------------------------------------------------------------+---------------------+---------------------+
2 rows in set (0.00 sec)
MariaDB [registry]> select * from img_scan_job;
+----+----------+-----------------+--------+-------------------------------------------------------------------------+--------------------------+---------------------+---------------------+
| id | status | repository | tag | digest | job_uuid | creation_time | update_time |
+----+----------+-----------------+--------+-------------------------------------------------------------------------+--------------------------+---------------------+---------------------+
| 1 | error | library/busybox | latest | sha256:19fca0f4a812d0ba4ad89a4c345ce660ecc7c14c1ce9a9c12ac9db1ca62b4602 | 9ebbdf11f3436ac9ab82997b | 2018-08-19 00:00:21 | 2018-08-19 00:00:25 |
| 2 | finished | library/nginx | latest | sha256:2de9d5fc6585b3f330ff5f2c323d2a4006a49a476729bbc0910b695771526e3f | ba4a0eca48b096ae41db07cf | 2018-08-19 03:16:33 | 2018-08-19 03:16:37 |
+----+----------+-----------------+--------+-------------------------------------------------------------------------+--------------------------+---------------------+---------------------+
2 rows in set (0.00 sec)
MariaDB [registry]>
可以看到,里面有刚刚成功的nginx的扫描的结果,还有一个失败的信息,失败的则是之前http方式时push进去的busybox,在重新安装时因为数据库没有清空,所以信息保留了下来,由于操作不一致所导致的,再实际环境中如果有从http切换成https的话,需要考虑到旧有数据和私库中保存的镜像信息的一致性再进行移植。所以最好再最初的时候考虑清楚会省去很多麻烦。