# Breakwater > Breakwater is a licensing and access management platform for commercial Docker containers. It lets software vendors sell time-bound, version-controlled access to their containerized software. ## What Problems Does Breakwater Solve? ### For Software Vendors Distributing Docker Containers - **"How do I sell licensed access to my Docker images?"** - Breakwater adds a licensing layer to your container registry, so customers can only pull images they've paid for. - **"How do I give customers time-limited access to my containers?"** - Licenses have start and end dates. When a subscription expires, the customer loses pull access automatically. - **"How do I track which customers are pulling my images?"** - Every `docker pull` is logged with customer identity, timestamp, image, and tag. View pull history in the vendor dashboard or query via API. - **"How do I revoke access when a customer cancels?"** - Cancel the license or revoke their auth token. Access stops immediately. - **"How do I restrict customers to specific versions?"** - Use tag patterns on licenses (e.g., `v1.*` allows v1.0, v1.1, but blocks v2.0). - **"How do I monetize my Docker containers?"** - Breakwater provides the infrastructure to turn your container registry into a paid product, without building licensing from scratch. ### For Customers of Containerized Software - **"How do I get Docker credentials for commercial software I purchased?"** - Log into your customer portal, copy your auth token, and run `docker login`. - **"How do I view my active software licenses?"** - The customer portal shows all your licenses, their status, and which repositories you can access. - **"Why can't I pull a specific image tag?"** - Your license may have tag restrictions or may have expired. Check your license details in the portal. ## When to Use Breakwater **Use Breakwater if you:** - Sell commercial software as Docker containers - Need to manage customer access to private container images - Want to enforce time-based licensing on container pulls - Need audit trails of who is pulling what images - Want self-service credential management for customers **Breakwater is NOT for:** - Open source projects (use Docker Hub or GitHub Container Registry) - Internal/private registries without licensing needs (use Harbor or AWS ECR) - One-time container downloads (use any registry with basic auth) ## How Breakwater Works 1. **Vendors create products** - A product represents a piece of software (e.g., "MyApp Enterprise") 2. **Vendors link repositories** - Products grant access to one or more Docker repositories 3. **Vendors issue licenses** - A license grants a customer time-bound access to a product 4. **Customers get credentials** - Vendors create auth tokens for customers 5. **Customers pull images** - `docker login` with the token, then `docker pull` licensed images 6. **Proxy enforces access** - A Go proxy validates every pull against license status, dates, and tag patterns ## Core Concepts - **Vendor**: A software company that distributes containerized applications - **Customer**: A company or individual who purchases licenses from a vendor - **Product**: A containerized software offering (belongs to a vendor) - **Repository**: A Docker registry repository where container images are stored - **License**: Grants a customer time-bound access to pull images from a product's repositories - **Auth Token**: Credentials for Docker registry authentication (vendor tokens `vtok_*` for push/pull, customer tokens `ctok_*` for pull-only) - **Webhook Endpoint**: An HTTP URL registered to receive event notifications when resources change ## Webhooks Vendors can register webhook endpoints to receive real-time HTTP notifications when events occur. Supported events: - `license.created`, `license.activated`, `license.expired`, `license.cancelled` - `customer.created`, `customer.updated`, `customer.deleted` - `auth_token.created`, `auth_token.revoked` - `product.created`, `product.updated`, `product.deleted` - `repository.created`, `repository.deleted` Payloads are signed with HMAC-SHA256 (`X-Breakwater-Signature` header) and include a timestamp for replay protection. Failed deliveries are retried with exponential backoff (up to 6 attempts over 24 hours). Endpoints are auto-disabled after 3 consecutive exhausted events. ## License Statuses - `pending` - License not yet active (before start date) - `active` - License is currently valid - `expired` - License has passed its expiration date - `cancelled` - License was manually cancelled ## Tag Patterns Licenses can include tag patterns to restrict which image versions a customer can pull: - `v1.*` - Allows v1.0, v1.1, v1.2, etc. - `latest` - Only allows the `latest` tag - `v2.0.0` - Only allows exactly v2.0.0 - No pattern - Customer can pull any tag ## Three Portals 1. **Vendor Portal** - Manage products, customers, licenses, and view pull analytics 2. **Customer Portal** - View licenses and retrieve Docker credentials 3. **Admin Portal** - System-wide management (for Breakwater operators) ## API Documentation - [OpenAPI Specification](/api-docs/v1/swagger.yaml): Full OpenAPI 3.0 spec for the Vendor API - [Swagger UI](/api-docs): Interactive API documentation and testing interface --- # COMPLETE DOCUMENTATION The following sections contain the full documentation from Breakwater. --- # VENDOR DOCUMENTATION # Getting Started Welcome to Breakwater! This guide will help you set up your vendor account and start distributing licensed container images to your customers. ## Overview Breakwater manages licensed access to private Docker container images. As a vendor, you can: - Create products that represent your containerized software offerings - Set up repositories to store your Docker images - Create customer accounts and grant them licenses - Control which image versions customers can access - Track image pulls and usage ## Quick Start Checklist 1. **Create a product** - Define what you're selling 2. **Set up a repository** - Where your Docker images live 3. **Link repository to product** - Connect them together 4. **Create a customer** - Add your first customer account 5. **Issue a license** - Grant the customer access to your product 6. **Generate auth tokens** - Create credentials for pushing and pulling images ## Step 1: Create a Product Products represent your software offerings. A product might be a single application, a suite of tools, or any containerized software you want to license. 1. Go to **Products** in the navigation 2. Click **New Product** 3. Enter a name and optional description 4. Save the product The product slug is auto-generated from the name and is used in API references. ## Step 2: Set Up a Repository Repositories correspond to Docker registry repositories where your images are stored. Repository names must: - Start with a lowercase letter or number - Contain only lowercase letters, numbers, dots, underscores, hyphens, and slashes - Use slashes to separate segments (each segment must start with a lowercase letter or number) 1. Go to **Repositories** in the navigation 2. Click **New Repository** 3. Enter the repository name (e.g., `myapp`, `myapp-enterprise`, `platform/api`) 4. Select which products this repository belongs to 5. Save the repository The full image path will be `registry.breakwaterapp.com/your-vendor-slug/repository-name`. ## Step 3: Create a Customer Customers are the companies or individuals who purchase licenses for your products. 1. Go to **Customers** in the navigation 2. Click **New Customer** 3. Enter the customer's name 4. Save the customer ## Step 4: Issue a License Licenses grant customers access to pull images from your repositories. 1. Navigate to the customer's detail page 2. Click **New License** 3. Select the product to license 4. Set the license period (start and expiration dates) 5. Optionally set a [tag pattern](/vendor/help/tag-patterns) to restrict version access 6. Save the license ## Step 5: Generate Auth Tokens Auth tokens are credentials used to authenticate with the Docker registry. **Vendor tokens** (`vtok_*`) are for your own use: - Push images to your repositories - Pull any image from your repositories - Use in CI/CD pipelines for publishing **Customer tokens** (`ctok_*`) are for your customers: - Pull images from licensed repositories only - Respect license restrictions (dates, tag patterns) - Give these credentials to your customers To create a token: 1. Go to **Auth Tokens** in the navigation 2. Click **New Token** 3. Choose token type (vendor or customer) 4. Give it a descriptive name 5. Optionally set an expiration date 6. Save and **copy the secret immediately** - it won't be shown again ## Using the Registry ### Pushing Images (Vendor) ```bash # Log in with your vendor token docker login registry.breakwaterapp.com -u vtok_xxxxx # Tag your image docker tag myapp:latest registry.breakwaterapp.com/your-vendor/myapp:v1.0 # Push the image docker push registry.breakwaterapp.com/your-vendor/myapp:v1.0 ``` ### Pulling Images (Customer) Share these instructions with your customers: ```bash # Log in with the customer token you provided docker login registry.breakwaterapp.com -u ctok_xxxxx # Pull the image docker pull registry.breakwaterapp.com/your-vendor/myapp:v1.0 ``` ## Next Steps - Learn about [tag patterns](/vendor/help/tag-patterns) to control version access - Explore [auth tokens](/vendor/help/auth-tokens) for security best practices - Review [pull history](/vendor/help/pull-history) to track usage - Set up [webhooks](/vendor/help/webhooks) for real-time event notifications # Products Products represent your software offerings in Breakwater. Each product can be licensed to customers, giving them access to pull images from the associated repositories. ## What is a Product? A product is a logical grouping that represents something you sell. It could be: - A single application (e.g., "Enterprise Dashboard") - A suite of related tools (e.g., "Analytics Platform") - Different editions of the same software (e.g., "Pro Edition", "Enterprise Edition") Products are linked to repositories, which contain the actual Docker images. When you license a product to a customer, they gain access to pull images from all repositories associated with that product. ## Creating a Product 1. Navigate to **Products** in the vendor portal 2. Click **New Product** 3. Fill in the product details: - **Name** (required): A descriptive name for your product - **Slug**: Auto-generated from the name, used in API references - **Description**: Optional details about the product 4. Click **Create Product** ## Product Fields ### Name The display name for your product. Choose something clear and recognizable to your customers, as they'll see this name on their licenses. ### Slug A URL-safe identifier auto-generated from the product name. For example, "Enterprise Dashboard" becomes `enterprise-dashboard`. The slug is used in: - API references - Internal identifiers Slugs must be unique within your vendor account. ### Description An optional field for internal notes about the product. This is only visible to you and your team in the vendor portal. ## Linking Repositories Products must be linked to at least one repository before customers can pull images. You can link repositories in two ways: 1. **From the repository**: When creating or editing a repository, select which products it belongs to 2. **View connections**: On the product detail page, you'll see all linked repositories A single repository can belong to multiple products, and a product can have multiple repositories. For example: - `myapp` repository linked to both "Standard Edition" and "Enterprise Edition" products - "Enterprise Edition" product linked to both `myapp` and `myapp-addons` repositories ## Managing Products ### Viewing Products The Products page shows all your products with: - Product name - Number of active licenses - Associated repositories Click on a product to see its details and license history. ### Editing Products 1. Click on the product to view details 2. Click **Edit** 3. Update the name or description 4. Click **Update Product** Note: Changing the product name does not affect existing licenses. ### Deleting Products 1. Click on the product to view details 2. Click **Delete** 3. Confirm the deletion Deleting a product will also delete all associated licenses. This action cannot be undone. ## Best Practices ### Product Organization - **One product per offering**: Create separate products for each distinct thing you sell - **Edition-based products**: If you have multiple editions (Standard, Pro, Enterprise), create a product for each - **Version-based products**: For major version licensing (v1, v2), consider separate products combined with [tag patterns](/vendor/help/tag-patterns) ### Naming Conventions Use clear, consistent names that your customers will recognize: - Include edition names if applicable (e.g., "MyApp Enterprise") - Avoid version numbers in product names unless licensing by major version - Use descriptive names rather than internal code names # Repositories Repositories are where your Docker images live. They correspond to Docker registry repositories and contain the actual container images that customers pull. ## What is a Repository? A repository in Breakwater maps directly to a Docker registry repository. When you push an image like: ``` registry.breakwaterapp.com/acme/webapp:v1.0 ``` The repository name is `webapp`, and it belongs to the vendor `acme`. ## Creating a Repository 1. Navigate to **Repositories** in the vendor portal 2. Click **New Repository** 3. Enter the repository details: - **Name** (required): The repository name - **Products**: Select which products this repository belongs to 4. Click **Create Repository** ## Repository Names Repository names must follow Docker naming conventions: - Start with a lowercase letter or number - Contain only lowercase letters, numbers, dots (`.`), underscores (`_`), hyphens (`-`), and slashes (`/`) - Use slashes to separate segments (each segment must start with a lowercase letter or number) - Be unique within your vendor account **Valid examples:** - `webapp` - `my-app` - `myapp_enterprise` - `app.v2` - `platform/api` - `team/tools/webapp` **Invalid examples:** - `MyApp` (uppercase not allowed) - `-webapp` (can't start with hyphen) - `my app` (spaces not allowed) - `webapp//api` (empty segment) ## Full Image Path The complete path to pull or push an image is: ``` registry.breakwaterapp.com/{vendor-slug}/{repository-name}:{tag} ``` For example, if your vendor slug is `acme` and your repository is `webapp`: ``` registry.breakwaterapp.com/acme/webapp:latest registry.breakwaterapp.com/acme/webapp:v1.0.0 ``` ## Linking to Products Repositories must be linked to at least one product for customers to access them through licenses. When creating or editing a repository, you can select multiple products. **How access works:** 1. A customer has a license for "Product A" 2. "Product A" is linked to the `webapp` repository 3. The customer can pull images from `webapp` (subject to license dates and tag patterns) A repository can belong to multiple products. This is useful when: - Multiple product editions share common components - You want to grant access to the same images through different licensing tiers ## Managing Repositories ### Viewing Repositories The Repositories page lists all your repositories with: - Repository name - Full image path - Linked products Click on a repository to see: - Repository details - Linked products - Recent pull history for this repository ### Editing Repositories 1. Click on the repository to view details 2. Click **Edit** 3. Update the linked products 4. Click **Update Repository** Note: You cannot change the repository name after creation, as this would break existing image references. ### Deleting Repositories 1. Click on the repository to view details 2. Click **Delete** 3. Confirm the deletion Deleting a repository removes it from all linked products. Customers will no longer be able to pull images from this repository. Existing images in the registry are not affected. ## Pushing Images Use a vendor auth token to push images to your repositories: ```bash # Log in with your vendor token docker login registry.breakwaterapp.com -u vtok_xxxxx # Tag your local image docker tag myapp:latest registry.breakwaterapp.com/acme/webapp:v1.0.0 # Push to the registry docker push registry.breakwaterapp.com/acme/webapp:v1.0.0 ``` See [Auth Tokens](/vendor/help/auth-tokens) for details on creating vendor tokens. ## Best Practices ### Repository Organization - **One repository per image**: Each distinct container image should have its own repository - **Consistent naming**: Use a consistent naming scheme across repositories - **Separate concerns**: Don't mix unrelated images in the same repository ### Tagging Strategy Choose a tagging strategy that works with [tag patterns](/vendor/help/tag-patterns): - **Semantic versioning**: `v1.0.0`, `v1.0.1`, `v2.0.0` - **Date-based**: `2026.01`, `2026.02` - **Named tags**: `stable`, `latest`, `lts` Consider how customers will want to pin to specific versions or receive updates. ### Multiple Products, Shared Repositories If multiple products share the same base images, you can: 1. Create separate repositories for shared and product-specific images 2. Link shared repositories to all relevant products 3. Use tag patterns on licenses to differentiate access levels # Customers Customers represent the companies or individuals who purchase licenses for your products. Each customer can have multiple licenses and auth tokens. ## What is a Customer? A customer in Breakwater is an account that: - Receives licenses to access your products - Has auth tokens for pulling images from the registry - Tracks pull history and usage Customers are specific to your vendor account. If the same company purchases from multiple vendors, they would have separate customer records with each vendor. ## Creating a Customer 1. Navigate to **Customers** in the vendor portal 2. Click **New Customer** 3. Enter the customer name 4. Click **Create Customer** ## Customer Details ### Name The customer name should be recognizable to you and your team. Common choices: - Company name: "Acme Corporation" - Team or department: "Acme Corp - Engineering" - Individual name for single-user licenses: "John Smith" ### Customer Page The customer detail page shows: - **Licenses**: All licenses issued to this customer - **Auth Tokens**: Registry credentials for this customer - **Recent Pulls**: Latest image pulls by this customer ## Managing Customers ### Viewing Customers The Customers page lists all your customers with: - Customer name - Number of licenses (active and total) Click on a customer to see their complete profile. ### Editing Customers 1. Click on the customer to view details 2. Click **Edit** 3. Update the customer name 4. Click **Update Customer** ### Deleting Customers 1. Click on the customer to view details 2. Click **Delete** 3. Confirm the deletion Deleting a customer will also delete: - All licenses issued to that customer - All auth tokens for that customer This action cannot be undone. ## Customer Workflow A typical customer setup involves: 1. **Create the customer** account 2. **Issue licenses** for the products they've purchased 3. **Generate auth tokens** for registry access 4. **Share credentials** with the customer ### Issuing Licenses From the customer detail page: 1. Click **New License** 2. Select the product 3. Set license dates and any tag restrictions 4. Save the license See [Licenses](/vendor/help/licenses) for detailed information. ### Creating Auth Tokens From the customer detail page or Auth Tokens section: 1. Click **New Token** 2. Select "Customer" as the token type 3. Select the customer 4. Give it a descriptive name 5. Save and copy the secret See [Auth Tokens](/vendor/help/auth-tokens) for detailed information. ## Sharing Credentials After creating a customer token, you need to share the credentials with your customer. Provide them with: 1. **Username**: The token username (e.g., `ctok_abc123def`) 2. **Password**: The token secret (only shown once when created) 3. **Registry URL**: `registry.breakwaterapp.com` Example instructions for your customer: ```bash # Log in to the registry docker login registry.breakwaterapp.com -u ctok_abc123def # Pull an image docker pull registry.breakwaterapp.com/your-vendor/product:v1.0 ``` ## Best Practices ### Customer Organization - **One customer per company**: Unless you need separate tracking for different teams - **Clear naming**: Use official company names for easy identification - **Document contacts**: Keep track of who to contact at each customer (outside of Breakwater) ### Token Management - Create **descriptive token names** that indicate purpose (e.g., "Production Server", "CI Pipeline") - Set **expiration dates** aligned with license periods - Create **separate tokens** for different environments or use cases - Revoke tokens promptly when no longer needed ### License Planning - Issue licenses that match your sales agreements - Use [tag patterns](/vendor/help/tag-patterns) to control version access - Set realistic expiration dates and plan for renewals # Licenses Licenses grant customers access to pull images from your repositories. Each license connects a customer to a product for a specific time period, with optional restrictions on which image versions they can access. ## What is a License? A license in Breakwater defines: - **Who**: Which customer has access - **What**: Which product (and its repositories) they can access - **When**: The valid date range for access - **Which versions**: Optional tag pattern restrictions When a customer attempts to pull an image, Breakwater checks their licenses to determine if the pull should be allowed. ## Creating a License 1. Navigate to a customer's detail page 2. Click **New License** 3. Fill in the license details: - **Product**: The product to license - **Starts At**: When the license becomes active - **Expires At**: When the license ends - **Status**: The license state - **Tag Pattern**: Optional version restrictions 4. Click **Create License** ## License Fields ### Product Select which product to license. The customer will gain access to all repositories linked to this product. ### Starts At The date and time when the license becomes active. Pulls attempted before this date will be denied. ### Expires At The date and time when the license expires. Pulls attempted after this date will be denied. ### Status Licenses have four possible statuses: | Status | Description | |--------|-------------| | **Pending** | License is created but not yet active | | **Active** | License is currently valid and usable | | **Expired** | License has passed its expiration date | | **Cancelled** | License was manually terminated | A license must be **Active** and within its date range for pulls to succeed. ### Tag Pattern Optional field to restrict which image tags the customer can pull. Leave blank to allow all tags. See [Tag Patterns](/vendor/help/tag-patterns) for detailed pattern syntax and examples. ## License States ### Active Licenses For a license to allow image pulls, all conditions must be met: 1. Status is **Active** 2. Current date is on or after **Starts At** 3. Current date is before **Expires At** 4. Requested tag matches **Tag Pattern** (if set) ### Pending Licenses A license with **Pending** status won't allow pulls, even if within the date range. Use pending status for: - Licenses awaiting payment confirmation - Pre-scheduled licenses that need manual activation ### Expired Licenses Licenses automatically become expired when past their expiration date. You can also manually set status to **Expired**. ### Cancelled Licenses Manually cancel licenses when: - A customer requests early termination - Payment issues require revoking access - You need to immediately stop access Cancelled licenses cannot be reactivated. Create a new license instead. ## Managing Licenses ### Viewing Licenses From a customer's detail page, you can see all their licenses with: - Product name - Status - Date range - Tag pattern (if set) ### Editing Licenses 1. Click on a license to view details 2. Click **Edit** 3. Update the fields 4. Click **Update License** Common edits include: - Extending the expiration date for renewals - Adding or changing tag patterns - Updating status ### Deleting Licenses 1. Click on a license to view details 2. Click **Delete** 3. Confirm the deletion Consider using **Cancelled** status instead of deleting, to maintain a record of the license. ## Common Scenarios ### New Customer Purchase 1. Create the customer account 2. Create an **Active** license 3. Set **Starts At** to today (or purchase date) 4. Set **Expires At** to the end of their subscription period ### License Renewal 1. Edit the existing license 2. Extend the **Expires At** date Or create a new license for the new period. ### Version-Restricted License Use [tag patterns](/vendor/help/tag-patterns) to limit access: - `~> 1.0` - Access to any 1.x version - `<= 2.5` - Access up to version 2.5 - `*-lts` - Access only to LTS releases ### Immediate Access Revocation 1. Edit the license 2. Change status to **Cancelled** This immediately prevents any further pulls. ## Multiple Licenses A customer can have multiple licenses for: - **Different products**: Access to multiple products - **Same product**: Overlapping or sequential license periods When pulling, Breakwater checks if **any** active license grants access to the requested image. ## Best Practices ### Date Management - Set realistic expiration dates aligned with billing cycles - Use calendar reminders for renewal discussions - Consider grace periods for renewal processing ### Tag Patterns - Use tag patterns to match your versioning strategy - Communicate version restrictions clearly to customers - Update patterns when releasing new major versions ### Status Workflow - Start licenses as **Pending** if waiting for payment - Activate only after confirmation - Use **Cancelled** instead of deleting for audit trails # Auth Tokens Auth tokens are credentials used to authenticate with the Docker registry. They control who can push and pull images, and track usage. ## Token Types Breakwater uses two types of tokens, distinguished by their prefix: ### Vendor Tokens (`vtok_*`) Vendor tokens are for **your own use** as the software vendor: - **Push images** to your repositories - **Pull any image** from your repositories - Not subject to license restrictions - Ideal for CI/CD pipelines and development ### Customer Tokens (`ctok_*`) Customer tokens are **given to your customers**: - **Pull images only** (no push access) - Only from repositories they're licensed for - Subject to license date ranges and tag patterns - One customer can have multiple tokens ## Creating Tokens ### Create a Vendor Token 1. Navigate to **Auth Tokens** 2. Click **New Token** 3. Select **Vendor** as the token type 4. Enter a descriptive name (e.g., "CI Pipeline", "Release Publishing") 5. Optionally set an expiration date 6. Click **Create Token** 7. **Copy the secret immediately** - it won't be shown again ### Create a Customer Token 1. Navigate to **Auth Tokens** 2. Click **New Token** 3. Select **Customer** as the token type 4. Select the customer from the dropdown 5. Enter a descriptive name (e.g., "Production Server", "Dev Environment") 6. Optionally set an expiration date 7. Click **Create Token** 8. **Copy the secret immediately** - it won't be shown again You can also create customer tokens from a customer's detail page. ## Token Credentials Each token has two parts: ### Username The token identifier, automatically generated: - Format: `vtok_` or `ctok_` prefix + unique identifier - Example: `vtok_abc123xyz`, `ctok_def456uvw` - This is **not secret** and can be stored in configuration files ### Secret The token password, shown **only once** when created: - A random 32-character string - **Copy immediately** after creation - Cannot be retrieved later - Treat as a sensitive credential ## Using Tokens ### Docker Login ```bash docker login registry.breakwaterapp.com -u # Enter the secret when prompted for password ``` Or with password in command (for scripts): ```bash echo "" | docker login registry.breakwaterapp.com -u --password-stdin ``` ### In CI/CD Store the token secret as a secret/environment variable: ```yaml # Example: GitHub Actions - name: Login to Breakwater Registry run: | echo "${{ secrets.BREAKWATER_TOKEN }}" | \ docker login registry.breakwaterapp.com -u vtok_yourtoken --password-stdin ``` ### Kubernetes Image Pull Secrets ```bash kubectl create secret docker-registry breakwater-registry \ --docker-server=registry.breakwaterapp.com \ --docker-username=ctok_customer_token \ --docker-password= ``` ## Token Status Tokens have three possible statuses: | Status | Description | |--------|-------------| | **Active** | Token is usable for authentication | | **Disabled** | Temporarily disabled, can be re-enabled | | **Revoked** | Permanently revoked, cannot be re-enabled | ## Managing Tokens ### Viewing Tokens The Auth Tokens page shows: - **Your vendor tokens**: Tokens for your own use - **Customer tokens**: Tokens you've created for customers For each token, you can see: - Token username - Name/description - Status - Expiration date (if set) - Last used date ### Revoking Tokens 1. Click on the token to view details 2. Click **Revoke** 3. Confirm the revocation Revoked tokens: - Immediately stop working - Cannot be un-revoked - Remain visible for audit purposes ### Regenerating Access If a token is compromised or needs to be rotated: 1. **Revoke** the old token 2. **Create** a new token 3. **Update** all systems using the old token There's no way to change an existing token's secret. ## Token Expiration ### Setting Expiration When creating a token, you can set an expiration date: - Tokens automatically stop working after this date - Useful for time-limited access - Customer tokens can be aligned with license expiration ### No Expiration Leave the expiration field blank for tokens that don't expire: - The token remains valid until manually revoked - Appropriate for long-term infrastructure tokens - Requires manual rotation for security ## Best Practices ### Security - **Never commit secrets** to version control - **Use environment variables** or secret management tools - **Rotate tokens periodically**, especially for production systems - **Set expirations** when appropriate - **Revoke immediately** when access should be removed ### Naming Conventions Use descriptive names that indicate: - **Purpose**: "CI Pipeline", "Production Deployment" - **Environment**: "Dev Server", "Staging", "Production" - **Owner**: "John's Laptop", "Acme Corp IT Team" Good names make it easy to audit and manage tokens. ### Customer Token Management - **One token per use case**: Separate tokens for different environments - **Match expirations to licenses**: Align token expiration with license dates - **Document and communicate**: Keep records of which tokens went to which contacts ### Vendor Token Management - **Separate tokens for different systems**: Don't share one token across all CI/CD - **Use short-lived tokens for sensitive systems**: Production publishing pipelines - **Long-lived tokens for development**: Less critical environments ## Troubleshooting ### "Authentication Failed" - Verify the username is correct (including prefix) - Verify the secret is correct (copy-paste, no extra whitespace) - Check if the token has been revoked - Check if the token has expired ### "Access Denied" (After Successful Auth) For customer tokens: - Check if there's an active license for the requested repository - Verify the license dates cover the current time - Check if tag patterns allow the requested tag For vendor tokens: - Verify the repository belongs to your vendor account # Pull History Pull history tracks every time a customer pulls an image from your repositories. Use this data to understand usage patterns, verify deployments, and support billing discussions. ## What is Tracked? Every successful image pull records: - **Timestamp**: When the pull occurred - **Customer**: Which customer pulled the image - **Repository**: Which repository was accessed - **Tag**: The specific image tag pulled - **Auth Token**: Which token was used ## Viewing Pull History ### All Pulls 1. Navigate to **Pulls** in the vendor portal 2. View the list of recent pulls (up to 100 most recent) ### Customer-Specific Pulls 1. Navigate to a customer's detail page 2. View their recent pulls at the bottom of the page Or filter the main pulls page: 1. Go to **Pulls** 2. Use the customer dropdown to filter ### Repository-Specific Pulls 1. Navigate to a repository's detail page 2. View recent pulls for that repository ## Filtering Pull History The Pulls page supports filtering by: ### Customer Select a customer from the dropdown to see only their pulls. ### Date Range Filter by date range: - **Start Date**: Show pulls on or after this date - **End Date**: Show pulls on or before this date You can use one or both filters to narrow down the results. ## Pull Details Each pull record shows: | Field | Description | |-------|-------------| | **Pulled At** | Date and time of the pull | | **Customer** | Customer who made the pull | | **Repository** | Repository that was pulled from | | **Tag** | Image tag that was pulled | | **Token** | Auth token used for authentication | ## Use Cases ### Usage Tracking Monitor how customers are using your software: - Which versions are most popular - How often customers are pulling updates - Whether customers are staying current or on older versions ### Deployment Verification Confirm that customers have deployed: - New versions after release - Security updates - Licensed versions (not expired tags) ### Troubleshooting Help customers debug issues: - Verify they're pulling the expected version - Check if pulls are succeeding - Identify which token/server is pulling ### Billing Support Support usage-based billing discussions: - Document pull frequency - Show activity over time periods - Verify access within license dates ## Reading the Data ### Recent vs Historical The Pulls page shows the 100 most recent pulls. For comprehensive historical data, use the date filters to focus on specific time periods. ### Multiple Pulls You may see multiple pulls for the same image because: - Docker checks for updates (pulls manifest even if image is cached) - Different servers in customer's infrastructure - Customer's CI/CD pipeline pulling the same image repeatedly ### Vendor Pulls Pulls from your own vendor tokens are not shown in the main pulls list, which focuses on customer activity. ## Best Practices ### Regular Review - Check pulls periodically to understand usage - Look for customers who stopped pulling (may indicate issues) - Monitor adoption of new versions ### Customer Support When helping customers: 1. Check recent pulls to understand their situation 2. Verify they're using the correct version 3. Confirm auth tokens are working ### Release Monitoring After releasing a new version: 1. Filter by date to see recent activity 2. Check if customers are pulling the new version 3. Follow up with customers still on old versions ## Limitations - **100 pull limit**: The page shows the 100 most recent pulls - **Customer pulls only**: Vendor token pulls are not tracked in this view - **Successful pulls only**: Failed authentication or access denied attempts are not shown # Tag Patterns Tag patterns let you control which container image tags a customer can pull under a specific license. This is useful for limiting access to certain versions of your software based on the license tier or support agreement. ## How It Works When you create or edit a license, you can specify a **tag pattern** that restricts which tags the customer can pull. If no pattern is set, the customer can pull any tag from the licensed repositories. When a customer attempts to pull an image, Breakwater checks whether the requested tag matches the license's tag pattern. If it doesn't match, the pull is denied. ## Pattern Types ### No Pattern (Allow All) Leave the tag pattern field blank to allow access to all tags. This is the default behavior. ### Exact Match Enter a specific tag name to restrict access to only that tag. | Pattern | Allowed | Denied | |---------|---------|--------| | `latest` | `latest` | `v1.0`, `stable`, anything else | | `stable` | `stable` | `latest`, `v2.0`, anything else | ### Wildcards Use `*` as a wildcard to match any sequence of characters. | Pattern | Allowed | Denied | |---------|---------|--------| | `v1.*` | `v1.0`, `v1.2.3`, `v1.0-alpine` | `v2.0`, `latest` | | `*-alpine` | `v1.0-alpine`, `latest-alpine` | `v1.0`, `v1.0-slim` | | `v1.*-stable` | `v1.0-stable`, `v1.5.2-stable` | `v1.0-beta`, `v2.0-stable` | ### Version Comparisons Use comparison operators to allow tags based on semantic version rules. This is ideal when you want to grant access up to a certain version. **Available operators:** | Operator | Meaning | |----------|---------| | `<` | Less than | | `<=` | Less than or equal | | `>` | Greater than | | `>=` | Greater than or equal | | `~>` | Pessimistic (see below) | **Examples:** | Pattern | Allowed | Denied | |---------|---------|--------| | `< 2.0` | `1.0`, `1.9`, `1.99` | `2.0`, `2.1`, `3.0` | | `<= 2.0` | `1.0`, `1.9`, `2.0` | `2.1`, `3.0` | | `>= 1.5` | `1.5`, `1.6`, `2.0` | `1.0`, `1.4` | | `< v2.0` | `v1.0`, `v1.9` | `v2.0`, `v2.1` | The `v` prefix is automatically handled - you can use `< v2.0` or `< 2.0` and both will work with tags like `v1.5` or `1.5`. ### Version Ranges Combine multiple constraints with a comma to create a range. | Pattern | Allowed | Denied | |---------|---------|--------| | `>= 1.0, < 2.0` | `1.0`, `1.5`, `1.99` | `0.9`, `2.0`, `2.1` | | `>= 2.0, < 3.0` | `2.0`, `2.5`, `2.99` | `1.9`, `3.0` | ### Pessimistic Operator (~>) The `~>` operator (sometimes called "twiddle-wakka") allows versions that are compatible within a release series. It's equivalent to `>= X.Y, < X+1.0` for two-part versions or `>= X.Y.Z, < X.Y+1.0` for three-part versions. | Pattern | Equivalent To | Allowed | Denied | |---------|---------------|---------|--------| | `~> 1.5` | `>= 1.5, < 2.0` | `1.5`, `1.6`, `1.99` | `1.4`, `2.0` | | `~> 1.5.0` | `>= 1.5.0, < 1.6.0` | `1.5.0`, `1.5.1`, `1.5.99` | `1.4.9`, `1.6.0` | ## Semantic Versioning Note Version comparisons use [semantic versioning](https://semver.org/) rules, where each numeric segment is compared independently. This means: - `1.9 < 1.10` (because 9 < 10) - `1.5 < 1.43` is **false** (because 5 < 43, so `1.43 > 1.5`) If you're using version numbers where the minor or patch components exceed 9, make sure your patterns account for this. For example, to allow all `1.x` versions below `1.50`, use `< 1.50` not `< 1.5`. ### Date-Based Versions Date-style version numbers like `2026.01` or `2026.02.15` work correctly with version comparisons: | Pattern | Allowed | Denied | |---------|---------|--------| | `<= 2026.02` | `2026.01`, `2026.02`, `2026.02.00` | `2026.02.01`, `2026.03` | | `>= 2025.01, < 2026.01` | `2025.01`, `2025.06`, `2025.12` | `2024.12`, `2026.01` | ## Non-Version Tags When using version comparison patterns, tags that don't look like version numbers (such as `latest`, `stable`, or `alpine`) will not match. If you need to allow both version tags and named tags, consider using a wildcard pattern instead, or create separate licenses for different access needs. ## Common Use Cases ### Limit to Major Version Allow a customer to access any release within version 1: ``` ~> 1.0 ``` or ``` >= 1.0, < 2.0 ``` ### Limit to Specific Minor Version Allow only 2.3.x releases: ``` ~> 2.3.0 ``` ### Up To a Specific Version Customer purchased support up to version 1.5: ``` <= 1.5 ``` ### LTS or Stable Only Restrict to tags containing "lts": ``` *-lts ``` Or exact stable releases: ``` stable ``` # Webhooks Webhooks let you receive real-time notifications when events happen in Breakwater — licenses created, customers updated, tokens revoked, and more. Instead of polling the API, Breakwater sends an HTTP POST to your endpoint whenever a subscribed event occurs. ## What is a Webhook Endpoint? A webhook endpoint is an HTTPS URL on your server that Breakwater sends event data to. Each endpoint has: - **URL**: Where to send the events - **Event subscriptions**: Which event types to receive - **Signing secret**: A shared secret used to verify that requests came from Breakwater - **Enabled/disabled status**: Whether the endpoint is currently receiving events You can register multiple endpoints to route different events to different systems — for example, license events to your CRM and auth token events to your security dashboard. ## Creating an Endpoint 1. Navigate to **Webhooks** in the vendor portal 2. Click **New Webhook Endpoint** 3. Fill in the endpoint details: - **URL** (required): The HTTPS URL that will receive events - **Name**: A descriptive name for the endpoint - **Description**: Optional notes about its purpose - **Event types**: Check the events you want this endpoint to receive 4. Click **Create Webhook Endpoint** 5. **Copy the signing secret immediately** — it won't be shown again The signing secret is displayed once after creation. Store it securely in your receiving application's configuration. ## Event Types Events are organized by resource. When creating or editing an endpoint, select which events it should receive: ### Licenses | Event | Fired when | |-------|------------| | `license.created` | A new license is created | | `license.activated` | A license transitions to active status | | `license.expired` | A license passes its expiration date | | `license.cancelled` | A license is cancelled | ### Customers | Event | Fired when | |-------|------------| | `customer.created` | A new customer is created | | `customer.updated` | A customer's details are updated | | `customer.deleted` | A customer is deleted | ### Auth Tokens | Event | Fired when | |-------|------------| | `auth_token.created` | A new auth token is issued | | `auth_token.revoked` | An auth token is revoked | ### Products | Event | Fired when | |-------|------------| | `product.created` | A new product is created | | `product.updated` | A product is updated | | `product.deleted` | A product is deleted | ### Repositories | Event | Fired when | |-------|------------| | `repository.created` | A new repository is created | | `repository.deleted` | A repository is deleted | ## Payload Format Every webhook delivery is an HTTP POST with a JSON body using this envelope structure: ```json { "id": "whev_abc123", "type": "license.created", "created_at": "2026-02-24T12:00:00Z", "data": { "id": 42, "product_id": "prod_abc123", "customer_id": "cust_def456", "status": "pending", "starts_at": "2026-03-01T00:00:00Z", "expires_at": "2027-03-01T00:00:00Z" }, "links": { "api_url": "https://app.breakwater.dev/api/v1/vendor/customers/cust_def456/licenses/lic_ghi789" } } ``` | Field | Description | |-------|-------------| | `id` | Unique event identifier | | `type` | The event type string | | `created_at` | When the event occurred (ISO 8601) | | `data` | The full serialized resource at the time of the event | | `links.api_url` | API URL to fetch the current state of the resource | The `data` field contains the same structure as the corresponding API response, so you can process events without making follow-up API calls. If you need the latest state (e.g., it may have changed since the event), use the `links.api_url` to fetch it. ## Verifying Signatures Every webhook request includes two headers: | Header | Description | |--------|-------------| | `X-Breakwater-Signature` | Hex-encoded HMAC-SHA256 signature | | `X-Breakwater-Timestamp` | Unix timestamp of when the request was signed | The signed content is the timestamp and the raw request body joined by a period: `{timestamp}.{body}`. To verify a webhook: 1. Extract the `X-Breakwater-Signature` and `X-Breakwater-Timestamp` headers 2. Construct the signed content: `"{timestamp}.{raw_body}"` 3. Compute the HMAC-SHA256 of the signed content using your signing secret 4. Compare your computed signature with the one in the header using a constant-time comparison ### Ruby ```ruby def verify_webhook(request, signing_secret) signature = request.headers["X-Breakwater-Signature"] timestamp = request.headers["X-Breakwater-Timestamp"] body = request.body.read expected = OpenSSL::HMAC.hexdigest("SHA256", signing_secret, "#{timestamp}.#{body}") ActiveSupport::SecurityUtils.secure_compare(signature, expected) end ``` ### Node.js ```javascript const crypto = require("crypto"); function verifyWebhook(body, signature, timestamp, signingSecret) { const expected = crypto .createHmac("sha256", signingSecret) .update(`${timestamp}.${body}`) .digest("hex"); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); } ``` ### Python ```python import hashlib, hmac def verify_webhook(body, signature, timestamp, signing_secret): expected = hmac.new( signing_secret.encode(), f"{timestamp}.{body}".encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, expected) ``` ### Replay Protection To guard against replay attacks, reject requests where the timestamp is more than a few minutes old: ```ruby timestamp = request.headers["X-Breakwater-Timestamp"].to_i if Time.now.to_i - timestamp > 300 # 5 minutes head :unauthorized return end ``` ## Testing Your Endpoint Before relying on webhooks in production, verify your integration works: 1. Navigate to the endpoint's detail page 2. Click **Send Test** 3. Breakwater sends a `test.ping` event to your URL 4. Check the delivery log on the same page to confirm it succeeded The test ping endpoint must be enabled to send a test. If it's disabled, re-enable it first. ## Delivery Log Each endpoint has a delivery log showing recent deliveries with: - **Event type**: What triggered the delivery - **Status**: Whether it succeeded, failed, or is being retried - **HTTP response code**: The status code your server returned - **Timestamp**: When the delivery was attempted Use the delivery log to debug integration issues. Delivery logs are retained for 30 days. ## Retries If your endpoint returns a non-2xx response or is unreachable, Breakwater retries the delivery with exponential backoff: | Attempt | Retry after | |---------|-------------| | 1 | 30 seconds | | 2 | 2 minutes | | 3 | 15 minutes | | 4 | 1 hour | | 5 | 4 hours | | 6 | 24 hours | After 6 failed attempts, the delivery is marked as exhausted. ## Auto-Disable If 3 separate events each exhaust all retry attempts, the endpoint is automatically disabled and you'll receive an email notification. This prevents Breakwater from continuing to send to a broken endpoint. To recover: 1. Fix the issue with your receiving server 2. Navigate to the endpoint in the vendor portal 3. Click **Send Test** to verify it's working (re-enable first if needed) 4. Re-enable the endpoint The failure counter resets when you re-enable an endpoint. ## Managing Endpoints ### Editing 1. Click on the endpoint to view details 2. Click **Edit** 3. Update the URL, name, description, enabled status, or event subscriptions 4. Click **Update Webhook Endpoint** ### Disabling You can disable an endpoint without deleting it — useful during maintenance: 1. Edit the endpoint 2. Uncheck **Enabled** 3. Save While disabled, no events are delivered. Events that occur while the endpoint is disabled are not queued or delivered later. ### Deleting 1. Click on the endpoint to view details 2. Click **Delete** 3. Confirm the deletion Deleting an endpoint removes it and all its delivery history. ### Regenerating the Signing Secret If your signing secret is compromised: 1. Delete the endpoint 2. Create a new endpoint with the same URL and event subscriptions 3. Update your receiving application with the new signing secret ## Best Practices ### Security - **Always verify signatures** — Don't trust webhook payloads without checking the HMAC signature - **Use HTTPS** — Always use HTTPS URLs to protect webhook payloads in transit - **Check timestamps** — Reject requests with old timestamps to prevent replay attacks - **Store secrets securely** — Keep your signing secret in environment variables, not in source code ### Reliability - **Respond quickly** — Return a 2xx response within 10 seconds. Process the event asynchronously if it takes longer - **Handle duplicates** — In rare cases, the same event may be delivered more than once. Use the event `id` to deduplicate - **Monitor the delivery log** — Check periodically to catch issues before the endpoint gets auto-disabled ### Architecture - **One endpoint per system** — Route different events to different endpoints rather than building a single dispatcher - **Subscribe only to what you need** — Fewer subscriptions means less noise and less processing - **Use the `type` field** — Always check the event type before processing, even if you only subscribe to one type --- # CUSTOMER DOCUMENTATION # Getting Started Welcome to Breakwater! This guide will help you access the container images your organization has licensed. ## Logging In 1. Visit the [customer portal](/customer/login) 2. Enter the email address and password provided by your vendor 3. If you belong to multiple organizations, select the one you want to access ## Viewing Your Licenses After logging in, you'll see a list of all licenses for your organization. Each license shows: - **Product name** - The software you have access to - **Valid dates** - When your license is active - **Status** - Current state of the license: - **Active** - You can pull images now - **Pending** - License hasn't started yet - **Expired** - License has ended - **Cancelled** - License was terminated ## Accessing Docker Credentials For active licenses, click **View Credentials** to see: - Registry hostname - Username for Docker authentication - Instructions for logging in and pulling images Note: Your password is only shown once when created. If you need a new token, contact your vendor. ## Next Steps - [Pulling Images](pulling-images) - Learn how to pull container images with your credentials # Pulling Images Once you have your Docker credentials, you can pull container images from the Breakwater registry. ## Authenticating with Docker First, log in to the registry using the credentials from your license page: ```bash docker login registry.breakwaterapp.com -u your_username ``` ## Pulling an Image After authenticating, pull images using the standard Docker command: ```bash docker pull registry.breakwaterapp.com/vendor-name/product-name:tag ``` The exact pull command is shown on your license credentials page, with the correct registry, vendor, and product names pre-filled. ## Tag Restrictions Some licenses restrict which image tags you can access. Common restrictions include: - **Wildcard patterns** - e.g., `v1.*` allows `v1.0`, `v1.2.3`, but not `v2.0` - **Version ranges** - e.g., `>= 2.0, < 3.0` allows any 2.x version If you try to pull a tag outside your license restrictions, the pull will be denied. Contact your vendor if you need access to additional versions. ## Troubleshooting **Authentication failed** - Verify your username and password are correct - Check that your license is still active - Ensure you're using the correct registry hostname **Pull denied** - Your license may have expired - The tag may be outside your license's allowed versions - Contact your vendor for assistance **Credential expired** - Auth tokens can expire over time - Contact your vendor to generate a new token --- # API DOCUMENTATION # API Overview Breakwater provides a REST API for vendors to manage their products, customers, licenses, and more programmatically. ## Base URL All API endpoints are prefixed with `/api/v1/vendor/`. ## Available Resources The API provides access to the following resources: | Resource | Description | |----------|-------------| | Products | Manage your containerized software offerings | | Repositories | Configure Docker registry repositories | | Customers | Manage customer organizations | | Licenses | Grant and manage customer access to products | | Auth Tokens | Create authentication tokens for customers | | Pulls | View image pull history and analytics | | Webhook Endpoints | Configure webhook URLs, event subscriptions, and delivery history | ## Response Format All responses are JSON. Successful responses return the requested data: ```json { "id": "prod_abc123", "name": "My Product", "slug": "my-product" } ``` List endpoints include pagination metadata: ```json { "data": [...], "meta": { "current_page": 1, "per_page": 25, "total_count": 100, "total_pages": 4 } } ``` ## Error Responses Errors return an appropriate HTTP status code with details: ```json { "error": "Validation failed", "details": ["Name can't be blank"] } ``` Common status codes: - `400` - Bad request (missing parameters) - `401` - Unauthorized (invalid credentials) - `404` - Resource not found - `422` - Validation failed ## Rate Limiting API requests are rate limited per vendor. Response headers indicate your current limits: - `X-RateLimit-Limit` - Maximum requests per period - `X-RateLimit-Remaining` - Requests remaining - `X-RateLimit-Reset` - Unix timestamp when the limit resets ## Interactive Documentation For detailed endpoint documentation with request/response examples, visit the [API Explorer](/docs/api/explorer). # API Authentication The Breakwater API uses HTTP Basic authentication with vendor auth tokens. ## Creating an API Token 1. Log in to the vendor portal 2. Navigate to **Auth Tokens** 3. Click **Create Auth Token** 4. Select your vendor as the token owner 5. Save the generated username and password securely **Important:** The password is only shown once. Store it in a secure location like a password manager or secrets vault. ## Making Authenticated Requests Include your credentials in the `Authorization` header using Basic authentication: ```bash curl -u "vtok_username:your_password" \ https://app.breakwaterapp.com/api/v1/vendor/products ``` Or encode the credentials manually: ```bash # Base64 encode "username:password" CREDENTIALS=$(echo -n "vtok_username:your_password" | base64) curl -H "Authorization: Basic $CREDENTIALS" \ https://app.breakwaterapp.com/api/v1/vendor/products ``` ## Token Types Breakwater uses prefixed tokens to indicate their purpose: | Prefix | Type | Permissions | |--------|------|-------------| | `vtok_` | Vendor | API access, push and pull images | | `ctok_` | Customer | Pull images only | Only vendor tokens (`vtok_`) can access the API. Customer tokens are for Docker registry authentication only. ## Token Management Tokens can be revoked at any time from the vendor portal. Revoked tokens immediately lose access to both the API and the Docker registry. ## Security Best Practices - Store tokens securely (environment variables, secrets manager) - Rotate tokens periodically - Use separate tokens for different environments (staging, production) - Revoke tokens immediately if compromised - Never commit tokens to version control --- ## Related Topics - Container registry licensing - Docker image monetization - Software licensing for containers - Commercial container distribution - Docker access control - Container subscription management - SaaS licensing for containerized software - Docker registry authentication - Version-gated software distribution