{"id":19096536,"url":"https://github.com/sapcc/keppel","last_synced_at":"2025-10-09T14:24:47.823Z","repository":{"id":37847832,"uuid":"140275624","full_name":"sapcc/keppel","owner":"sapcc","description":"Regionally federated multi-tenant container image registry","archived":false,"fork":false,"pushed_at":"2025-10-01T14:52:04.000Z","size":21702,"stargazers_count":113,"open_issues_count":4,"forks_count":10,"subscribers_count":51,"default_branch":"master","last_synced_at":"2025-10-01T16:34:55.611Z","etag":null,"topics":["container-registry","kubernetes","openstack"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sapcc.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-07-09T11:25:25.000Z","updated_at":"2025-10-01T14:52:08.000Z","dependencies_parsed_at":"2023-10-23T09:37:10.266Z","dependency_job_id":"f4533a03-44e1-4e50-9183-64cd10afde4a","html_url":"https://github.com/sapcc/keppel","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sapcc/keppel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sapcc%2Fkeppel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sapcc%2Fkeppel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sapcc%2Fkeppel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sapcc%2Fkeppel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sapcc","download_url":"https://codeload.github.com/sapcc/keppel/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sapcc%2Fkeppel/sbom","scorecard":{"id":731462,"data":{"date":"2025-08-11","repo":{"name":"github.com/sapcc/keppel","commit":"2dc82e88e7800a4d1e5b31207723471650e46145"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":6.6,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":3,"reason":"Found 5/14 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":10,"reason":"30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":8,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: topLevel 'checks' permission set to 'write': .github/workflows/checks.yaml:19","Info: topLevel 'contents' permission set to 'read': .github/workflows/checks.yaml:20","Info: topLevel 'contents' permission set to 'read': .github/workflows/ci.yaml:23","Info: topLevel 'actions' permission set to 'read': .github/workflows/codeql.yaml:21","Info: topLevel 'contents' permission set to 'read': .github/workflows/codeql.yaml:22","Warn: topLevel 'security-events' permission set to 'write': .github/workflows/codeql.yaml:23","Info: topLevel 'contents' permission set to 'read': .github/workflows/oci-distribution-conformance.yml:18","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":6,"reason":"branch protection is not maximal on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'master'","Info: 'force pushes' disabled on branch 'master'","Warn: 'branch protection settings apply to administrators' is disabled on branch 'master'","Info: 'stale review dismissal' is required to merge on branch 'master'","Info: required approving review count is 2 on branch 'master'","Info: codeowner review is required on branch 'master'","Info: 'last push approval' is required to merge on branch 'master'","Warn: no status checks found to merge onto branch 'master'","Info: PRs are required in order to make changes on branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: SAST configuration detected: CodeQL","Info: all commits (21) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/checks.yaml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/checks.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/checks.yaml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/checks.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/checks.yaml:34: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/checks.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/checks.yaml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/checks.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/checks.yaml:54: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/checks.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/ci.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/ci.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:45: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/ci.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:47: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/ci.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yaml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/codeql.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yaml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/codeql.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yaml:37: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/codeql.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yaml:42: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/codeql.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yaml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/codeql.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/oci-distribution-conformance.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/oci-distribution-conformance.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/oci-distribution-conformance.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/oci-distribution-conformance.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/oci-distribution-conformance.yml:57: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/oci-distribution-conformance.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/oci-distribution-conformance.yml:74: update your workflow using https://app.stepsecurity.io/secureworkflow/sapcc/keppel/oci-distribution-conformance.yml/master?enable=pin","Warn: containerImage not pinned by hash: Dockerfile:4","Warn: containerImage not pinned by hash: Dockerfile:14: pin your Docker image by updating alpine:3.22 to alpine:3.22@sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1","Warn: goCommand not pinned by hash: .github/workflows/checks.yaml:57","Warn: goCommand not pinned by hash: .github/workflows/ci.yaml:62","Info:   0 out of  14 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   4 third-party GitHubAction dependencies pinned","Info:   0 out of   2 containerImage dependencies pinned","Info:   0 out of   2 goCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}}]},"last_synced_at":"2025-08-22T14:33:02.460Z","repository_id":37847832,"created_at":"2025-08-22T14:33:02.461Z","updated_at":"2025-08-22T14:33:02.461Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279001533,"owners_count":26083117,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["container-registry","kubernetes","openstack"],"created_at":"2024-11-09T03:37:00.707Z","updated_at":"2025-10-09T14:24:47.817Z","avatar_url":"https://github.com/sapcc.png","language":"Go","readme":"\u003c!--\nSPDX-FileCopyrightText: 2025 SAP SE\n\nSPDX-License-Identifier: Apache-2.0\n--\u003e\n\n# Keppel, a multi-tenant container image registry\n\n[![CI](https://github.com/sapcc/keppel/actions/workflows/ci.yaml/badge.svg)](https://github.com/sapcc/keppel/actions/workflows/ci.yaml)\n[![Conformance Test](https://github.com/sapcc/keppel/actions/workflows/oci-distribution-conformance.yml/badge.svg)](https://github.com/sapcc/keppel/actions/workflows/oci-distribution-conformance.yml)\n[![Coverage Status](https://coveralls.io/repos/github/sapcc/keppel/badge.svg?branch=master)](https://coveralls.io/github/sapcc/keppel?branch=master)\n[![Go Report Card](https://goreportcard.com/badge/github.com/sapcc/keppel)](https://goreportcard.com/report/github.com/sapcc/keppel)\n\nIn this document:\n\n- [Overview](#overview)\n- [History](#history)\n- [Terminology](#terminology)\n- [Usage](#usage)\n\nIn other documents:\n\n- [Operator guide](./docs/operator-guide.md)\n- [API specification](./docs/api-spec.md)\n- [Notes for developers/contributors](./CONTRIBUTING.md)\n\n## Overview\n\nWhen working with the container ecosystem (Docker, Kubernetes, etc.), you need a place to store your container images.\nThe default choice is the [Docker Registry](https://github.com/docker/distribution), but a Docker Registry alone is not\nenough in productive deployments because you also need a compatible OAuth2 provider. A popular choice is\n[Harbor](https://goharbor.io), which bundles a Docker Registry, an auth provider, and some other tools. Another choice\nis [Quay](https://github.com/quay/quay), which implements the registry protocol itself, but is otherwise very similar to\nHarbor.\n\nHowever, Harbor's architecture is limited by its use of a single registry that is shared between all users. Most\nimportantly, by putting the images of all users in the same storage, quota and usage tracking gets unnecessarily\ncomplicated. Keppel instead uses multi-tenant-aware storage drivers so that each customer gets their own separate\nstorage space. Storage quota and usage can therefore be tracked by the backing storage. This orchestration is completely\ntransparent to the user: A unified API endpoint is provided that multiplexes requests to their respective registry\ninstances.\n\nKeppel fully implements the [OCI Distribution API][dist-api], the standard API for container image registries. It also\nprovides a [custom API](docs/api-spec.md) to control the multitenancy added by Keppel and to expose additional metadata\nabout repositories, manifests and tags. Other unique features of Keppel include:\n\n- **cross-regional federation**: Keppel instances running in different geographical regions or different network\n  segments can share their account name space and provide seamless replication between accounts of the same name on\n  different instances.\n- **online garbage collection**: Unlike Docker Registry, Keppel can perform all garbage collection tasks without\n  scheduled downtime or any other form of operator intervention.\n- **vulnerability scanning**: Keppel can use [Trivy](https://trivy.dev/) to perform vulnerability scans on its contents.\n\n[dist-api]: https://github.com/opencontainers/distribution-spec\n\n## History\n\nIn its first year, leading up to 1.0, Keppel used to orchestrate a fleet of docker-registry instances to provide the\nOCI Distribution API. We hoped to save ourselves the work of reimplementing the full Distribution API, since Keppel\nwould only have to reverse-proxy customer requests into their respective docker-registry. Over time, as Keppel's feature\nset grew, more and more API requests were intercepted to track metadata, validate requests and so forth. We ended up\nscrapping the docker-registry fleet entirely to make Keppel much easier to deploy and manage. It's now conceptually more\nsimilar to Quay than to Harbor, but retains its unique multi-tenant storage architecture.\n\n## Terminology\n\nWithin Keppel, an **account** is a namespace that gets its own backing storage. The account name is the first path\nelement in the name of a repository. For example, consider the image `keppel.example.com/foo/bar:latest`. It's\nrepository name is `foo/bar`, which means it's located in the Keppel account `foo`.\n\nAccess is controlled by the account's **auth tenant** or just **tenant**. Note that tenants and accounts are separate\nconcepts: An account corresponds to one backing storage, and a tenant corresponds to an authentication/authorization\nscope. Each account is linked to exactly one auth tenant, but there can be multiple accounts linked to the same auth\ntenant.\n\nInside an account, you will find **repositories** containing **blobs**, **manifests** and **tags**. The meaning of those\nterms is the same as for any other Docker registry or OCI image registry, and is defined in the [OCI Distribution API\nspecification][dist-api].\n\n## Usage\n\nBuild with `make`, install with `make install` or `docker build`. The resulting `keppel` binary contains client commands\nas well as server commands.\n\n- For how to use the client commands, run `keppel --help`.\n- For how to deploy the server components, please refer to the [operator guide](./docs/operator-guide.md).\n\n## Support, Feedback, Contributing\n\nThis project is open to feature requests/suggestions, bug reports etc. via [GitHub issues](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/creating-an-issue). Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, as well as additional contribution information, see our [Contribution Guidelines](./CONTRIBUTING.md).\n\n## Security / Disclosure\n\nIf you find any bug that may be a security problem, please follow our instructions [in our security policy](https://github.com/SAP-cloud-infrastructure/.github/blob/main/SECURITY.md) on how to report it. Please do not create GitHub issues for security-related doubts or problems.\n\n## Code of Conduct\n\nWe as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone. By participating in this project, you agree to abide by its [Code of Conduct](https://github.com/SAP-cloud-infrastructure/.github/blob/main/CODE_OF_CONDUCT.md) at all times.\n\n## Licensing\n\nCopyright 2018-2025 SAP SE or an SAP affiliate company and keppel contributors. Please see our [LICENSE](./LICENSE) for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available [via the REUSE tool](https://api.reuse.software/info/github.com/sapcc/keppel).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsapcc%2Fkeppel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsapcc%2Fkeppel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsapcc%2Fkeppel/lists"}