Your First Private Registry
Set up a registry with user authentication and access control policies.
What You'll Learn
By the end of this tutorial, you will:
- Create a user with password authentication
- Configure an access control policy
- Test authenticated push and pull operations
Prerequisites
- Completed the Quickstart tutorial
- Angos binary available
Step 1: Generate a Password Hash
Angos uses Argon2 for secure password hashing. Generate a hash for your user:
./angos argon
When prompted, enter a password. The tool outputs an Argon2 hash:
Input Password:
$argon2id$v=19$m=19456,t=2,p=1$...
Copy this hash for the next step.
Step 2: Configure Authentication
Update your config.toml to add a user identity:
[server]
bind_address = "0.0.0.0"
port = 8000
[blob_store.fs]
root_dir = "./registry-data"
[repository."test"]
[auth.identity.alice]
username = "alice"
password = "$argon2id$v=19$m=19456,t=2,p=1$..." # Paste your hash here
Step 3: Add an Access Control Policy
Add a global access policy that requires authentication:
[global.access_policy]
default = "deny"
rules = [
"identity.username != null"
]
Your complete config.toml should now look like:
[server]
bind_address = "0.0.0.0"
port = 8000
[blob_store.fs]
root_dir = "./registry-data"
[auth.identity.alice]
username = "alice"
password = "$argon2id$v=19$m=19456,t=2,p=1$..."
[global.access_policy]
default = "deny"
rules = [
"identity.username != null"
]
[repository."test"]
Step 4: Configure Docker for Insecure Registry
Since this tutorial uses HTTP (no TLS), configure Docker to allow insecure connections.
Edit or create /etc/docker/daemon.json:
{
"insecure-registries": ["localhost:8000"]
}
Then restart Docker:
# Linux
sudo systemctl restart docker
# macOS (Docker Desktop)
# Restart Docker Desktop from the menu bar
Step 5: Start the Registry
./angos -c config.toml server
Step 6: Test Anonymous Access (Should Fail)
Try to push without authentication:
docker tag alpine:latest localhost:8000/test/alpine:latest
docker push localhost:8000/test/alpine:latest
You should see an authentication error:
unauthorized: Access denied
Step 7: Login and Push
Login with your credentials:
docker login localhost:8000 -u alice
Enter your password when prompted. Now push the image:
docker push localhost:8000/test/alpine:latest
The push should succeed.
Step 8: Verify the Configuration
You can also verify using curl:
# Without auth (should fail)
curl http://localhost:8000/v2/
# With auth (should succeed)
curl -u alice:yourpassword http://localhost:8000/v2/
Understanding the Policy
The access policy uses CEL (Common Expression Language):
rules = [
"identity.username != null"
]
This rule allows access when identity.username is set, meaning the client has authenticated with valid credentials. For anonymous clients identity.username is null, so the rule does not match.
What's Next?
Now that you have a private registry, you can:
- Add more users: Create additional
[auth.identity.<name>]sections - Fine-grained policies: See How to Set Up Access Control for repository-specific rules
- Use OIDC: See Configure GitHub Actions OIDC for token-based authentication
- Enable TLS: See Configure mTLS for encrypted connections
Reference
- CEL Expressions Reference - All available variables and functions
- Configuration Reference - Complete configuration options