The RegistryAdmin is the docker registry UI tool that allows users to manage access and entries of a private Docker
registry.
It provides a web-based user interface for managing repositories, images, and user access, and allows users to
authenticate using either password
. The main goal of the project is to provide a high-level API for managing user access
to a private registry, and to restrict user actions (such as push and pull) for specific repositories based on
the official private Docker registry image.
This can be useful for registry owners who want to have more control over their registry and who want to be able to manage access
to it more easily.
Web user interface created with React-Admin framework and MUI components.
pull
/push
) for token
authentication scheme)RegistryAdmin is a tool that works in conjunction with a private Docker registry and uses the
registry's V2 API
to communicate with it. It has the HTTP endpoint that is used to authenticate users using a token and to check their
access rights.
In order to use RegistryAdmin with a registry, the registry must be configured to support token-based authentication.
This allows users to be granted or restricted access to certain actions (such as pull
or push
) based on their
authentication token.
# in registry config file
...
auth:
token:
realm: https://{registry-admin-host}/api/v1/registry/auth
service: container_registry_service_name
issuer: registry_token_issuer_name
rootcertbundle: /certs/cert.crt # path to certificate bundle
You can use the htpasswd
authentication scheme, but with this method you can only manage users and not restrict access
to repositories by specific user. This feature is only available when using token-based authentication.
To enhance the user experience with features such as sorting, searching, and autocompleting, RegistryAdmin has an embedded storage system that synchronizes with the data in the registry. This is necessary to avoid the limits of the search API (catalog) exposed by the registry API, as the search function only allows pagination with a cursor and does not support searching by repository entry. The app also includes an internal garbage collector for check data consistency in the embedded storage.
For catch changes in the registry, you should configure registry notification to be sent to the RegistryAdmin app.
# in registry config file
...
notifications:
events:
includereferences: true
endpoints:
- name: ra-listener
disabled: false
url: http://{registry-admin-host}/api/v1/registry/events
headers:
Authorization: [ Basic Y2xpZW50MDg6Y0t1cnNrQWdybzA4 ]
timeout: 1s
threshold: 5
backoff: 3s
ignoredmediatypes:
- application/octet-stream
ignore:
mediatypes:
- application/octet-stream
Access to RegistryAdmin UI based on users role:
Admin
- full rights to read and write for users, access and entries of repositories.Manager
- limited rights for browse access list and repositories entries.User
- can browse assigned repositories entries only.RegistryAdmin distributed as a small self-contained binary as well as a docker image. Binary support multiple architectures and multiple operating systems, including linux_x86_64, linux_arm64, linux_arm, macos_x86_64, macos_arm64 and windows_x86_64. Docker image support linux_x86_64, linux_arm64 and linux_arm architectures.
Latest stable version has :vX.Y.Z docker tag (with :latest alias) and the current master has :master tag.
To get started, you will need to set up the required parameters in a docker-compose file or using command line flags. You can find various configuration examples in the _examples folder.
When you start RegistryAdmin as docker container you should set permission for application
folders (certs
,config
,data
) user with UID 1001
. For override UID inside a container you should use environment
variable in a container starting parameters APP_UID
.
chown -R 1001:1001 {root-registry-admin-folder}
hostname
- define host name or IP address to include in the AllowedOrigins
header which is used to check
for CORS
requests
port
- define the port that the application will use to listen for HTTP requests (the default is 80).
Note: If you start the app as a Docker container, only ports 80
and 443
are exposed inside container.
store.type
- define storage type for store main data (users, accesses, repositories). Default (embed
)
Now implement embed storage type only
store.admin_password
- overrides the default admin password when storage creating first (default password: admin
)store.embed.path
- define pathname for embed storage file (default: ./data.db
)registry.host
- define main host or IP address of private registry instance with protocol scheme prefix.
example: host: https://{registry-host}
registry.port
- port of a private docker registry instance (default: 5000
)registry.auth_type
- defines authenticate type token
or basic
(default: token
).issuer
- issuer name which checks inside registry, issuer name must be same at private docker registry and RegistryAdmin.service
- service name which defined in registry settings, service name must be same at private docker registry and RegistryAdmin.❗ Keep a mind for token
auth type required certs
options must be defined.
registry.certs.path
- root directory where will be generated and stored certificates for token signingregistry.certs.key
- path to private key for token signingregistry.certs.public_key
- path to public key for verify token signregistry.certs.ca
- path to certificate authority bundleregistry.certs.fqdns
- FQDN(s) required to add for registry certificate and checks at request from clientsregistry.certs.ip
- an IP address will add to certificate extension field (SANs). If it omitted certificate error can be occurred.Certificates will be generated automatically if registry.certs.path
is valid and directory is empty. If certs
options isn't defined certificates will be created at a user home directory in sub folder .registry-certs
:
~/.registry-certs/
registry_auth.key
registry_auth.pub
registry_auth_ca.crt
Notice: when self-signed certificates is used you should configure Docker Engine on a client host for work with ones.
# https://docs.docker.com/config/daemon/
# /etc/docker/daemon.json (Linux)
# C:ProgramDatadockerconfigdaemon.json (Windows)
{
...
"insecure-registries": ["{registry-host}:{port}"],
...
}
Certificates generated for registry token also can be using for HTTP TLS/SSL. That certificate automatically add to trusted CA.
But if you use another certificate for HTTPS access you should add it to trusted CA pool. For it use option
--registry.https-certs
for define path to a used certificate which using for TLS/SSL access. It's also required for certificates
issued by Let's Encrypt. Also, you can define --registry.https-insecure
option for skips check for the trusted certificate,
but in NOT RECOMMENDED.
# in a registry-admin config
registry:
...
certs:
...
https_cert: /{path-to-ssl}/cert.pem
...
Keep in mind if you use auto
ssl mode you must define --ssl.acme-location
option for store ACME cache. Then cache
date should be define in registry
config in letsencrypt
option:
letsencrypt:
cachefile: /path/to/cache-file
email: [email protected]
hosts: [you-registry.domain.org]
Supported registry V2 only. For use docker registry with token authentication you need configure it as a standalone access control manager for resources hosted by other services which wish to authenticate and manage authorization using a separate access control manager. For get more information about it, follow to the official documentations.
At first, you need define auth
option for token
auth and set specific certificate
and key
which generated with
the RegistryAdmin app. Token options must be the same as RegistryAdmin Registry
defined
options (issuer
,service
,cert_ca
). The RegistryAdmin app has public endpoint for authenticate users requests to
registry,
that must be used in realm
registry option.
https://{registry-admin-host}:{port}/api/v1/auth
❗ realm
is option of IP address or Hostname RegistryAdmin instance that must accessible for docker
clients which
uses it for authenticate to private registry.
auth:
token:
realm: http://{registry-admin-hostname}/api/v1/registry/auth
service: container_registry
issuer: registry_token_issuer
rootcertbundle: /certs/cert.crt
For handle registry event and trigger repository task (such add new, update or delete repository entry) you should set up registry notification options:
url
- http(s) url to RegistryAdmin host with events endpoint path.
Authorization
any enabled and registered user and its password in the RegistryAdmin app, encoded in Base64.
notifications:
events:
includereferences: true
endpoints:
- name: ra-listener
disabled: false
url: http://registry-admin/api/v1/registry/events
headers:
Authorization: [Basic YWRtaW46c3VwZXItc2VjcmV0] # encoded in Base64 as 'admin:super-secret'
timeout: 1s
threshold: 5
backoff: 3s
ignoredmediatypes:
- application/octet-stream
ignore:
mediatypes:
- application/octet-stream
basic
option using .htpasswd
file and doesn't support restrict access to specific repositories. For use basic
authentication you required following options:
login
- username for access to docker registrypassword
- password for access to docker registryDocker registry reads .htpasswd
file every time when authenticate call and doesn't require restart the registry
service
after user update or delete in RegistryAdmin
By default, no request log generated. This can be turned on by setting --logger.enabled
. The log (auto-rotated)
has Apache Combined Log Format
User can also turn stdout log on with --logger.stdout
. It won't affect the file logging above but will output some
minimal info about processed requests, something like this:
127.0.0.1 - - [06/Dec/2022:18:36:34 +0300] "GET /auth/user HTTP/2.0" 200 159
127.0.0.1 - - [06/Dec/2022:18:36:34 +0300] "GET /api/v1/registry/auth HTTP/2.0" 200 198
When RegistryAdmin has access from Internet you should minimal set up security rules for prevent password brute force.
The simplest way using fail2ban
service with access log file on a docker host.
access.log
for RegistryAdmin service# in registry-admin config file
logger:
enabled: true
filename: /var/log/registry-admin/access.log # mount the directory to a docker host folder for get access for fail2ban
max_size: 5M
max_backups: 3
filter
with rule for the registry-admin
service which handle 401
and 403
auth/z errors# /etc/fail2ban/filter.d/registry-admin.conf
[Definition]
failregex = ^<HOST> .+" 40[1,3] d+ .*$
ignoreregex =
fail2ban
action at chain statement, because normal system
traffic traditionally comes across on the INPUT
chain, while Docker container traffic is sent through the FORWARD
chain.# in the /etc/fail2ban/action.d/ directory
sudo cp iptables-common.conf iptables-common-forward.conf
sudo sed -i 's/INPUT/FORWARD/g' iptables-common-forward.conf
sudo cp iptables-multiport.conf iptables-multiport-forward.conf
sudo sed -i 's/iptables-common.conf/iptables-common-forward.conf/g' iptables-multiport-forward.conf
jail
with the registry-admin
rule# in /etc/fail2ban/jail.local
[registry-admin]
enabled = true
port = http,https # or set your custom port
filter = registry-admin
banaction = iptables-multiport-forward
logpath = /{path-to-logs-mounted-dir}/logs/access.log
maxretry = 5
findtime = 1h
bantime = 1d
Each option can be provided in three forms: command line, environment key:value pair or config file (json
or yaml
formats).
Command line options have a long form only, like --hostname=localhost. The environment key (name) listed
for each option as a suffix, i.e. [$HOSTNAME].
Config file allowed in both format json
and yml
--listen: listen on host:port (127.0.0.1:80/443 without) (default: *) [$RA_LISTEN]
--hostname: Main hostname of service (default: localhost) [$RA_HOST_NAME]
--port: Main web-service port. Default:80 (default: 80) [$RA_PORT]
--config-file: Path to config file [$RA_CONFIG_FILE]
--debug enable the debug mode [$RA_DEBUG]
registry:
--registry.host: Main host or address to docker registry service [$RA_REGISTRY_HOST]
--registry.port: Port which registry accept requests. Default:5000 (default: 5000) [$RA_REGISTRY_PORT]
--registry.auth-type:[basic|token] Type for auth to docker registry service. Available 'basic' and 'token'. Default 'token' (default: token) [$RA_REGISTRY_AUTH_TYPE]
--registry.login: Username is a credential for access to registry service using basic auth type [$RA_REGISTRY_LOGIN]
--registry.password: Password is a credential for access to registry service using basic auth type [$RA_REGISTRY_PASSWORD]
--registry.htpasswd: Path to htpasswd file when basic auth type selected [$RA_REGISTRY_HTPASSWD]
--registry.https-insecure Set https connection to registry insecure [$RA_REGISTRY_HTTPS_INSECURE]
--registry.service: A service name which defined in registry settings [$RA_REGISTRY_SERVICE]
--registry.issuer: A token issuer name which defined in registry settings [$RA_REGISTRY_ISSUER]
--registry.token-ttl: Define registry auth token TTL (in seconds). Default value 60 seconds. [$RA_REGISTRY_TOKEN_TTL]
--registry.gc-interval: Use for define custom time interval for garbage collector execute (minutes), default 1 hours [$RA_REGISTRY_GC_INTERVAL]
certs:
--registry.certs.path: A path to directory where will be stored new self-signed cert,keys and CA files, when 'token' auth type is used [$RA_REGISTRY_CERTS_CERT_PATH]
--registry.certs.key: A path where will be stored new self-signed private key file, when 'token' auth type is used [$RA_REGISTRY_CERTS_KEY_PATH]
--registry.certs.public-key: A path where will be stored new self-signed public key file, when 'token' auth type is used [$RA_REGISTRY_CERTS_PUBLIC_KEY_PATH]
--registry.certs.ca-root: A path where will be stored new CA bundles file, when 'token' auth type is used [$RA_REGISTRY_CERTS_CA_ROOT_PATH]
--registry.certs.fqdn: FQDN(s) for registry certificates [$RA_REGISTRY_CERTS_FQDN]
--registry.certs.ip: Address which appends to certificate SAN (Subject Alternative Name) [$RA_REGISTRY_CERTS_IP]
--registry.https-certs: A path to a HTTPS certificate used for TLS access to registry instance [$RA_REGISTRY_HTTPS_CERT]
auth:
--auth.token-secret: Main secret for auth token sign [$RA_AUTH_TOKEN_SECRET]
--auth.jwt-issuer: Token issuer signature (default: zebox) [$RA_AUTH_ISSUER_NAME]
--auth.jwt-ttl: Define JWT expired timeout (default: 1h) [$RA_AUTH_JWT_TTL]
--auth.cookie-ttl: Define cookies expired timeout (default: 24h) [$RA_AUTH_COOKIE_TTL]
logger:
--logger.stdout enable stdout logging [$RA_LOGGER_STDOUT]
--logger.enabled enable access and error rotated logs [$RA_LOGGER_ENABLED]
--logger.file: location of access log (default: access.log) [$RA_LOGGER_FILE]
--logger.max-size: maximum size before it gets rotated (default: 10M) [$RA_LOGGER_SIZE]
--logger.max-backups: maximum number of old log files to retain (default: 10) [$RA_LOGGER_BACKUPS]
ssl:
--ssl.type:[none|static|auto] ssl (auto) support. Default is 'none' (default: none) [$RA_SSL_TYPE]
--ssl.cert: path to cert.pem file [$RA_SSL_CERT]
--ssl.key: path to key.pem file [$RA_SSL_KEY]
--ssl.acme-location: dir where certificates will be stored by autocert manager (default: ./acme) [$RA_SSL_ACME_LOCATION]
--ssl.acme-email: admin email for certificate notifications [$RA_SSL_ACME_EMAIL]
--ssl.port: Main web-service secure SSL port. Default:443 (default: 443) [$RA_SSL_PORT]
--ssl.http-port: http port for redirect to https and acme challenge test (default: 80) [$RA_SSL_ACME_HTTP_PORT]
--ssl.fqdn: FQDN(s) for ACME certificates [$RA_SSL_ACME_FQDN]
store:
--store.type:[embed] type of storage (default: embed) [$RA_STORE_DB_TYPE]
--store.admin-password: Define password for default admin user when storage create first (default: admin) [$RA_STORE_ADMIN_PASSWORD]
embed:
--store.embed.path: Parent directory for the sqlite files (default: ./data.db) [$RA_STORE_EMBED_DB_PATH]
Help Options:
-? Show this help message
-h, --help Show this help message
frontend
development you should run RegistryAdmin with defined environment variable
RA_DEV_HOST=http://127.0.0.1:3000
for prevent CORS
error in a browser. Also .env.development
must contain valid
development hostname of RegistryAdmin.engine
interface and can be used for extends supported storage
typeEmbed
uses SQLite
database and required CGO
enabledThe project is under active development and may have breaking changes till v1 is released. However, we are trying our best not to break things unless there is a good reason.
This project was inspired by projects and ideas of Umputun