Through the Looking Glass: Queen Alice

This is post 7 in a seven-part series on what the Anchore Enterprise API makes possible for container security teams.

By the final chapter of Through the Looking-Glass, Alice has crossed the entire chessboard, reached the eighth square, and been crowned. She has gone from a bewildered visitor to a Queen — someone who understands the rules of Wonderland well enough to command them. That’s the right frame for where we’ve arrived in this series. We’ve explored SBOM data, built event-driven pipelines, queried across the fleet with GraphQL, investigated zero-day blast radius, and diffed vulnerability profiles between container image versions. What remains is the layer underneath all of that: the platform itself.

Account creation, user provisioning, permission grants, registry configuration — these are the administrative tasks that typically live in a runbook or get performed manually through the UI when onboarding a new team or environment. Every one of them is available through the API, which means they can be scripted, version-controlled, and integrated into whatever infrastructure automation your organization already relies on. The kingdom runs better when the Queen doesn’t have to sign every scroll by hand.

Drawing the Borders: Account Management

In Anchore Enterprise, accounts provide the top-level isolation boundary — separate teams, environments, or tenants each get their own account with their own container images, policies, and users. They’re the territories on the chessboard. Creating one via the API is a single call, available only to admin users:

curl -s -u _api_key:<your-api-key> \
  -X POST "https://wonderland.example.com/v2/accounts" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "mad-hatter-team",
    "email": "[email protected]"
  }'

Accounts can be enabled or disabled independently of deletion — useful for temporarily suspending access without losing configuration:

curl -s -u _api_key:<your-api-key> \
  -X PUT "https://wonderland.example.com/v2/accounts/mad-hatter-team/state" \
  -H "Content-Type: application/json" \
  -d '{"state": "disabled"}'

Deleting an account requires it to be in a disabled state first — a safeguard against accidental removal of active resources:

# Disable first
curl -s -u _api_key:<your-api-key> \
  -X PUT "https://wonderland.example.com/v2/accounts/mad-hatter-team/state" \
  -H "Content-Type: application/json" \
  -d '{"state": "disabled"}'

# Then delete
curl -s -u _api_key:<your-api-key> \
  -X DELETE "https://wonderland.example.com/v2/accounts/mad-hatter-team"

Calling the Court Together: User Management

An account without users is a kingdom without subjects. Users are created within an account context, and because user and credential management cannot be performed with API key authentication, these calls must use username/password credentials:

curl -s -u admin:password \
  -X POST "https://wonderland.example.com/v2/accounts/mad-hatter-team/users" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "alice",
    "password": "changeme123",
    "user_type": "native"
  }'

For production use, users should authenticate with API keys rather than passwords. As covered in the first post in this series, API keys are created per user and use the _api_key username convention — and importantly, must be created using username/password credentials, not an existing API key.

Three Cheers for Queen Alice: Granting Roles with RBAC

At Alice’s coronation feast, the Red Queen and White Queen tested whether she deserved her crown. Anchore RBAC is the reverse — once you have the authority, you decide who gets what title. Creating a user doesn’t grant them any access on its own; permissions in Anchore Enterprise are managed through RBAC roles. To see the full list of available roles in your deployment:

curl -s -u _api_key:<your-api-key> \
  "https://wonderland.example.com/v2/rbac-manager/roles" \
  | jq '.[].name'

To grant a user a role within a specific account, POST to the role’s members endpoint with the username and the account as the domain_name:

curl -s -u _api_key:<your-api-key> \
  -X POST "https://wonderland.example.com/v2/rbac-manager/roles/full-control/members" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "alice",
    "domain_name": "mad-hatter-team"
  }'

Roles can be revoked just as easily:

curl -s -u _api_key:<your-api-key> \
  -X DELETE "https://wonderland.example.com/v2/rbac-manager/roles/full-control/members?username=alice&domain_name=mad-hatter-team"

Opening the Gates: Registry Configuration

For Anchore to analyze container images from private registries, the gates have to be opened — the registry needs to be configured with the appropriate credentials. This too is fully API-driven:

curl -s -u _api_key:<your-api-key> \
  -X POST "https://wonderland.example.com/v2/registries" \
  -H "Content-Type: application/json" \
  -H "x-anchore-account: mad-hatter-team" \
  -d '{
    "registry": "registry.wonderland.example.com:5000",
    "registry_name": "internal-registry",
    "registry_user": "anchore-svc",
    "registry_pass": "s3cr3t",
    "registry_verify": true
  }'

The x-anchore-account header scopes the registry to the target account — each account manages its own registry credentials independently.

Decreeing the Laws: System Configuration

A queen sets the rules of the kingdom. Anchore Enterprise exposes a set of platform-level configuration settings through the API — things that affect system-wide behavior rather than individual accounts or users. These settings are viewable and updatable without requiring a config file change or service restart in many cases, making them well-suited for automation.

To see everything that’s configurable along with current values, descriptions, and whether a restart is required to apply a change:

curl -s -u _api_key:<your-api-key> \
  "https://wonderland.example.com/v2/system/configurations" \
  | jq '.items[] | {key: .key, value: .value, requires_restart: .requires_system_restart, description: .description}'

The full schema for all configurable settings — including valid values, types, and constraints — is available at a dedicated endpoint, useful for tooling that needs to validate inputs before applying them:

curl -s -u _api_key:<your-api-key> \
  "https://wonderland.example.com/v2/system/configurations/schema" \
  | jq .

To read the current value of a specific configuration key:

curl -s -u _api_key:<your-api-key> \
  "https://wonderland.example.com/v2/system/configurations/<config_key>" \
  | jq .

To update a single setting:

curl -s -u _api_key:<your-api-key> \
  -X PUT "https://wonderland.example.com/v2/system/configurations/<config_key>" \
  -H "Content-Type: application/json" \
  -d '{"key": "<config_key>", "value": "<new_value>"}'

To update multiple settings atomically in a single call — if any key fails validation, none are applied:

curl -s -u _api_key:<your-api-key> \
  -X PATCH "https://wonderland.example.com/v2/system/configurations" \
  -H "Content-Type: application/json" \
  -d '[
    {"key": "<config_key_1>", "value": "<value_1>"},
    {"key": "<config_key_2>", "value": "<value_2>"}
  ]'

To reset a setting back to its system default:

curl -s -u _api_key:<your-api-key> \
  -X DELETE "https://wonderland.example.com/v2/system/configurations/<config_key>"

Each configuration response includes a requires_system_restart field — worth checking before applying changes in a production environment, as some settings only take effect after the relevant service is restarted. The source field on each setting tells you where the current value originated: default, api, or config_file — useful for understanding whether a setting has been previously overridden and by what mechanism.

The Royal Proclamation: Team Provisioning Script

The real value of administrative automation is composing these operations into a repeatable provisioning workflow — one proclamation that calls a whole new team into being. The script below accepts a team name and a list of users, and handles the full onboarding sequence: account creation, user creation, role assignment, and registry configuration:

import requests

ANCHORE_URL = "https://wonderland.example.com/v2"

# admin API key for account, RBAC, and registry operations
AUTH = ("_api_key", "<your-admin-api-key>")

# username/password required for user + credential operations
USER_MGMT_AUTH = ("admin", "<your-admin-password>")

def create_account(name, email=None):
    body = {"name": name}
    if email:
        body["email"] = email
    resp = requests.post(
        f"{ANCHORE_URL}/accounts", json=body, auth=AUTH
    )
    resp.raise_for_status()
    print(f"  Created account: {name}")
    return resp.json()

def create_user(account, username, password, user_type="native"):
    resp = requests.post(
        f"{ANCHORE_URL}/accounts/{account}/users",
        json={
            "username": username,
            "password": password,
            "user_type": user_type,
        },
        auth=USER_MGMT_AUTH,  # API keys cannot manage users or credentials
    )
    resp.raise_for_status()
    print(f"  Created user: {username} in {account}")

def grant_role(username, account, role="full-control"):
    resp = requests.post(
        f"{ANCHORE_URL}/rbac-manager/roles/{role}/members",
        json={"username": username, "domain_name": account},
        auth=AUTH,
    )
    resp.raise_for_status()
    print(f"  Granted role '{role}' to {username} in {account}")

def add_registry(account, registry, user, password, verify_ssl=True):
    resp = requests.post(
        f"{ANCHORE_URL}/registries",
        json={
            "registry": registry,
            "registry_user": user,
            "registry_pass": password,
            "registry_verify": verify_ssl,
        },
        auth=AUTH,
        headers={"x-anchore-account": account},
    )
    resp.raise_for_status()
    print(f"  Configured registry: {registry} for {account}")

def provision_team(account_name, users, registry=None):
    print(f"\nProvisioning account: {account_name}")
    create_account(account_name)
    for user in users:
        create_user(account_name, user["username"], user["password"])
        grant_role(
            user["username"],
            account_name,
            user.get("role", "read-only"),
        )
    if registry:
        add_registry(
            account_name,
            registry["host"],
            registry["user"],
            registry["password"],
        )
    print(f"\nDone. Account '{account_name}' is ready.\n")

if __name__ == "__main__":
    provision_team(
        account_name="mad-hatter-team",
        users=[
            {
                "username": "alice",
                "password": "changeme123",
                "role": "full-control",
            },
            {
                "username": "hatter",
                "password": "changeme456",
                "role": "read-only",
            },
        ],
        registry={
            "host": "registry.wonderland.example.com:5000",
            "user": "anchore-svc",
            "password": "s3cr3t",
        },
    )

This kind of script slots naturally into an infrastructure-as-code workflow — driven by a configuration file, triggered by a CI pipeline, or invoked as part of a larger onboarding automation. The operations are idempotent enough to be re-run safely with appropriate error handling, and the entire provisioning history becomes auditable through your version control system rather than buried in UI click trails.

End of the Looking-Glass Country

Alice begins Through the Looking-Glass as a confused visitor and ends it as a Queen presiding over the chessboard she once didn’t understand. The arc of this series is meant to be similar. We’ve worked through the structure of the API, the data it surfaces, the events it emits, the questions you can ask of it, and now the platform itself. What you do with all of that is finally up to you.

The thread running through all seven posts is the same: Anchore Enterprise exposes a comprehensive, well-structured API, and the container security teams that get the most out of it are the ones who treat it as a platform to build on rather than a UI to click through. The examples in this series are starting points. Your environment, your tooling, and your workflows will take them somewhere specific to you.

Thanks for reading. If you’re an Anchore Enterprise customer looking to build with the API, the Customer Success team is the fastest way to get unblocked — reach out through the Anchore Support Portal. If you’re not a customer yet but want to see what any of this looks like against your own container images, request a demo and we’ll walk you through it.