https://github.com/dvob/hati
Harbor Token Issuer
https://github.com/dvob/hati
Last synced: 11 days ago
JSON representation
Harbor Token Issuer
- Host: GitHub
- URL: https://github.com/dvob/hati
- Owner: dvob
- Created: 2025-11-08T17:19:50.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2025-11-08T17:38:35.000Z (7 months ago)
- Last Synced: 2026-04-18T21:07:24.329Z (about 2 months ago)
- Language: Go
- Size: 40 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# hati
The **HA**arbor **T**oken **I**ssuer allows you to obtain short lived robot account tokens by authenticating using JWT tokens. This allows you to easily access Harbor without the hassle of token management.
Essentially this means that you configure Hati to trust your platform (`-jwks-url`) which could be your Gitlab instance, Github a Kubernetes Cluster, etc. (see examples below).
Then you obtain a JWT token from your platform which you in turn exchange for a Harbor Robot Account token via a HTTP request.
```
curl -X POST -H "Authorization: Bearer $YOUR_PLATFORM_JWT" "https://hati.yourdomain.com/?project=mytest&permission=push"
```
```
{
"user": "robot$mytest+hati-ghjashebhbf",
"secret": "THE_ROBOT_ACCOUNT_TOKEN"
}
```
Then you can login using:
```
echo $hati_secret | docker login --username $hati_user harbor.yourdomain.com --password-stdin
```
Authorization is performed based on the claims in the JWT token and rules written in [CEL](https://cel.dev/) and/or [JavaScript](https://github.com/robertkrimen/otto/blob/master/README.md).
CEL:
```
claims.sub == "repo:dvob/ci-test:ref:refs/heads/main"
```
JavaScript:
```
function isAuthorized(project, permission, claims) {
return claims.sub === "repo:dvob/ci-test:ref:refs/heads/main"
}
```
# Examples
## Gitlab
* Example Pipeline: [.gitlab-ci.yml](./examples/gitlab-ci.yml)
* Example Hati configuration
```
hati -jwks-url https://gitlab.com/oauth/discovery/keys \
-harbor-url https://harbor.yourdomain.com \
-harbor-user admin \
-harbor-password Harbor12345
-skip-audience-check=true
-cel-file=examples/rule-gitlab.cel
```
* Docs concerning Gitlab id_tokens: https://docs.gitlab.com/ci/secrets/id_token_authentication/
CEL rule to permit specific Gitlab repository:
```
claims.sub == "project_path:dvob/hati-test:ref_type:branch:ref:main"
```
## Github
* Example Pipeline: [github-workflow.yml](./examples/github-workflow.yml)
* Example Hati configuration
```
hati -jwks-url=https://token.actions.githubusercontent.com/.well-known/jwks \
-harbor-url https://harbor.yourdomain.com \
-harbor-user admin \
-harbor-password Harbor12345
-skip-audience-check=true
-cel-file=examples/rule-github.cel
```
* Docs concerning Github OIDC tokens: https://docs.github.com/en/actions/reference/security/oidc#oidc-token-claims
CEL rule to permit specific Github repository:
```
claims.sub == "repo:dvob/ci-test:ref:refs/heads/main"
```
# Deployment
In the directory manifets you find the manifests to deploy Hati along side a Harbor instance which got installed using the [Harbor Helm Chart](https://github.com/goharbor/harbor-helm).
Before you can use it you have to configure the follogin things accordingly:
- set ingress host name (Ingress)
- configure rules to your needs (ConfigMaps)
- configure JWSK URL (Deployment)
```
kubectl -n harbor apply -f manifests/
```
# Caveats
Minimum lifetime of a robot account is one day. For each successfully authenticated and authorized request we create a new robot account.
So if you have many requests you will end up with many many robot accounts.
Currently you need the admin user with password as system robot accounts are not able to create robot accounts due to a bug (https://github.com/goharbor/harbor/issues/21406).
An alternative to Hati would be Hashicorp Vault with a plugin for Harbor: https://github.com/manhtukhang/vault-plugin-harbor