#!/usr/bin/env nu # Configure access policies for OCI registry namespaces export def main [ --registry-url: string = "localhost:5000" --registry-type: string = "zot" --admin-password: string = "admin" ] { print "šŸ”’ Configuring OCI registry access policies..." print $" Registry: ($registry_url)" print $" Type: ($registry_type)\n" let policies = get-policy-definitions match $registry_type { "zot" => { configure-zot-policies $registry_url $policies } "harbor" => { configure-harbor-policies $registry_url $policies $admin_password } "distribution" => { configure-distribution-policies $registry_url $policies } _ => { print $"⚠ Unknown registry type: ($registry_type)" } } print "\nāœ… Policy configuration complete!" } def get-policy-definitions [] -> list { [ { namespace: "provisioning-extensions" access: { authenticated: { read: true write: true delete: true } anonymous: { read: false write: false delete: false } } users: [ {name: "provisioning", role: "admin"} {name: "developer", role: "developer"} ] webhooks: [ { event: "push" url: "http://orchestrator:8080/registry/events/push" } { event: "delete" url: "http://orchestrator:8080/registry/events/delete" } ] } { namespace: "provisioning-kcl" access: { authenticated: { read: true write: true delete: false } anonymous: { read: false write: false delete: false } } users: [ {name: "provisioning", role: "admin"} {name: "developer", role: "developer"} ] webhooks: [ { event: "push" url: "http://orchestrator:8080/registry/events/push" } ] } { namespace: "provisioning-platform" access: { authenticated: { read: true write: false delete: false } anonymous: { read: false write: false delete: false } } users: [ {name: "provisioning", role: "admin"} ] webhooks: [ { event: "push" url: "http://orchestrator:8080/registry/events/push" } ] } { namespace: "provisioning-test" access: { authenticated: { read: true write: true delete: true } anonymous: { read: true write: false delete: false } } users: [ {name: "provisioning", role: "admin"} {name: "developer", role: "developer"} {name: "tester", role: "developer"} ] webhooks: [] } ] } def configure-zot-policies [registry_url: string, policies: list] { print "Configuring Zot policies..." print "\nℹ Zot policies are configured in config.json" print " The following policies are defined:\n" for policy in $policies { print $"šŸ“¦ ($policy.namespace):" print $" Authenticated users:" print $" Read: ($policy.access.authenticated.read)" print $" Write: ($policy.access.authenticated.write)" print $" Delete: ($policy.access.authenticated.delete)" print $" Anonymous users:" print $" Read: ($policy.access.anonymous.read)" print $" Users: ($policy.users | get name | str join ', ')" if ($policy.webhooks | length) > 0 { print $" Webhooks: ($policy.webhooks | length) configured" } print "" } print "ℹ To update policies, edit zot/config.json and restart the registry" } def configure-harbor-policies [ registry_url: string policies: list admin_password: string ] { print "Configuring Harbor policies via API...\n" let auth = $"admin:($admin_password)" | encode base64 for policy in $policies { print $"šŸ“¦ Configuring ($policy.namespace)..." # Get project ID let project_id = get-harbor-project-id $registry_url $policy.namespace $auth if ($project_id | is-empty) { print $" ⚠ Project not found, skipping" continue } # Configure RBAC configure-harbor-rbac $registry_url $project_id $policy.users $auth # Configure webhooks if ($policy.webhooks | length) > 0 { configure-harbor-webhooks $registry_url $project_id $policy.webhooks $auth } print $" āœ“ Policies configured" print "" } } def get-harbor-project-id [ registry_url: string project_name: string auth: string ] -> int { let result = (do { http get $"http://($registry_url)/api/v2.0/projects?name=($project_name)" --headers { "Authorization": $"Basic ($auth)" } } | complete) if $result.exit_code == 0 { let projects = ($result.stdout | from json) if ($projects | length) > 0 { return ($projects | first | get project_id) } } return null } def configure-harbor-rbac [ registry_url: string project_id: int users: list auth: string ] { print " Configuring RBAC..." for user in $users { let role_id = match $user.role { "admin" => 1 "developer" => 2 "guest" => 3 _ => 2 } let member_body = { role_id: $role_id member_user: { username: $user.name } } let result = (do { http post $"http://($registry_url)/api/v2.0/projects/($project_id)/members" $member_body --headers { "Authorization": $"Basic ($auth)" "Content-Type": "application/json" } } | complete) if $result.exit_code == 0 { print $" āœ“ User ($user.name) added as ($user.role)" } else { if ($result.stderr | str contains "already exists") { print $" ℹ User ($user.name) already exists" } else { print $" ⚠ Error adding user ($user.name)" } } } } def configure-harbor-webhooks [ registry_url: string project_id: int webhooks: list auth: string ] { print " Configuring webhooks..." for webhook in $webhooks { let webhook_body = { name: $"webhook-($webhook.event)" description: $"Webhook for ($webhook.event) events" enabled: true event_types: [$webhook.event] targets: [ { type: "http" address: $webhook.url skip_cert_verify: true } ] } let result = (do { http post $"http://($registry_url)/api/v2.0/projects/($project_id)/webhook/policies" $webhook_body --headers { "Authorization": $"Basic ($auth)" "Content-Type": "application/json" } } | complete) if $result.exit_code == 0 { print $" āœ“ Webhook for ($webhook.event) configured" } else { print $" ⚠ Error configuring webhook for ($webhook.event)" } } } def configure-distribution-policies [registry_url: string, policies: list] { print "Configuring Distribution policies...\n" print "ℹ Distribution uses htpasswd for authentication" print " Generating htpasswd file...\n" # Collect all unique users let all_users = ($policies | each { |p| $p.users } | flatten | get name | uniq) print "Users to create:" for user in $all_users { print $" - ($user)" } print "\nℹ To create users, run:" print " htpasswd -Bc htpasswd " print "\nℹ Access control is enforced at the authentication layer" print " All authenticated users can push/pull" print " Anonymous users can only pull if allowed in config.yml" } # Helper: Show policy for namespace export def "policy show" [ namespace: string ] { let policies = get-policy-definitions let policy = ($policies | where namespace == $namespace | first) if ($policy | is-empty) { print $"Policy for namespace ($namespace) not found" return } print $"Policy for: ($policy.namespace)\n" print "Access Control:" print " Authenticated users:" print $" Read: ($policy.access.authenticated.read)" print $" Write: ($policy.access.authenticated.write)" print $" Delete: ($policy.access.authenticated.delete)" print " Anonymous users:" print $" Read: ($policy.access.anonymous.read)" print $" Write: ($policy.access.anonymous.write)" print $" Delete: ($policy.access.anonymous.delete)" print "\nUsers:" for user in $policy.users { print $" - ($user.name) (($user.role))" } if ($policy.webhooks | length) > 0 { print "\nWebhooks:" for webhook in $policy.webhooks { print $" - Event: ($webhook.event)" print $" URL: ($webhook.url)" } } } # Helper: List all policies export def "policy list" [] -> table { let policies = get-policy-definitions $policies | each { |p| { namespace: $p.namespace auth_read: $p.access.authenticated.read auth_write: $p.access.authenticated.write anon_read: $p.access.anonymous.read users: ($p.users | length) webhooks: ($p.webhooks | length) } } }