You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A number of Kubernetes operators, including[FluxCD](https://fluxcd.io/) and [upbound/provider-terraform](https://github.com/upbound/provider-terraform), often need to authenticate with the GitHub API, particularly when private repositories are used. This may be to clone a private repository, pull from a private GHCR repository, or to send a commit or deployment status. Common practice is to use Personal Access Tokens (PATs), but their use is far from optimal: PATs tending to be long-lived, poorly scoped, and tied to an individual, as GitHub has no official support for service accounts.
12
+
Kubernetes operators like[FluxCD](https://fluxcd.io/) and [crossplane-contrib/provider-terraform](https://github.com/crossplane-contrib/provider-terraform)need GitHub API access for private repositories, container registry pulls, and status updates. The traditional approaches have critical flaws: Personal Access Tokens (PATs) are long-lived, over-privileged, and tied to individuals, while storing GitHub App private keys in-cluster creates massive security risks.
13
13
14
-
This operator functions similarly to cert-manager, but instead of managing certificates, it manages GitHub App Installation Access Tokens. It takes custom-scoped `Token` (namespaced) and `ClusterToken` requests and transforms them into `Secrets`. These `Secrets` contain regularly refreshed GitHub App Installation Access Token credentials. These credentials are ready for use with GitHub clients that rely on HTTP Basic Auth, providing a more secure and automated solution for token management.
14
+
This operator solves the problem by functioning like cert-manager for GitHub tokens. It automatically generates ephemeral, fine-grained access tokens from GitHub App credentials stored securely in cloud Key Management Services, never exposing private keys in your cluster.
15
+
16
+
## Features
17
+
18
+
-**🔐 Zero-Trust Security**: Never store GitHub App private keys in-cluster - integrates with AWS KMS, Google Cloud KMS, and HashiCorp Vault
19
+
-**⏰ Ephemeral & Auto-Rotating**: Tokens expire in 1 hour and refresh automatically before expiration
20
+
-**🎯 Fine-Grained Permissions**: Each token can have different scopes, down to specific repositories and permissions
21
+
-**🏢 Multi-Tenancy**: Namespace isolation with `Token` CRD, cluster-wide control with `ClusterToken`
-**📊 Production-Ready**: Prometheus metrics, health probes, intelligent retry logic with exponential backoff
15
24
16
25
## Getting Started
17
26
18
27
### Prerequisites
19
28
20
-
* A Kubernetes cluster (v1.21+)
21
-
* A [GitHub App](https://docs.github.com/en/apps/creating-github-apps) with permissions and repository assignments sufficient to meet the needs of all anticipated GitHub API interactions. Typically: `metadata: read`, `contents: read`, `statuses: write`.
22
-
* Specifically: App ID, App Installation ID and a Private Key are required.
The operator itself requires configuration via `ConfigMap/gtm-config` in its deployment namespace. This contains the GitHub App ID, Installation ID and Private Key provider details. In addition to embedding the private key file within the secret, AWS Key Management Service (KMS), Google Cloud Key Management, and HashiCorp Vault's Transit Secrets Engine are also supported for secure external handling of keying material.
33
-
34
-
#### Example `gtm-config` with embedded Private Key
45
+
Configure via `Secret/gtm-config` with your GitHub App details and secure key storage:
35
46
36
47
```yaml
48
+
# AWS KMS (recommended)
37
49
apiVersion: v1
38
50
kind: Secret
39
51
metadata:
@@ -43,17 +55,12 @@ stringData:
43
55
gtm.yaml: |
44
56
app_id: 1234
45
57
installation_id: 4567890
46
-
provider: file
47
-
key: /config/private.key
48
-
private.key: |
49
-
-----BEGIN RSA PRIVATE KEY-----
50
-
...elided...
51
-
-----END RSA PRIVATE KEY-----
58
+
provider: aws
59
+
key: alias/github-token-manager
52
60
```
53
61
54
-
#### Example `gtm-config` with AWS KMS
55
-
56
62
```yaml
63
+
# File-based (for development/testing)
57
64
apiVersion: v1
58
65
kind: Secret
59
66
metadata:
@@ -62,18 +69,36 @@ metadata:
62
69
stringData:
63
70
gtm.yaml: |
64
71
app_id: 1234
65
-
installation_id: 45678890
66
-
provider: aws
67
-
key: alias/github-token-manager
72
+
installation_id: 4567890
73
+
provider: file
74
+
key: /config/private.key
75
+
private.key: |
76
+
-----BEGIN RSA PRIVATE KEY-----
77
+
...your GitHub App private key...
78
+
-----END RSA PRIVATE KEY-----
68
79
```
69
80
70
-
### `Token` and `ClusterToken`
81
+
**Cloud KMS Permissions Required:**
82
+
83
+
- **AWS KMS**: IAM permissions `kms:DescribeKey` and `kms:Sign` on the KMS key
84
+
- **GCP KMS**: Permission `cloudkms.cryptoKeyVersions.useToSign` or role `roles/cloudkms.cryptoKeyVersionsSigner`
85
+
- **Vault**: Policy with `write` capability on transit sign path (e.g., `transit/sign/<keyName>`)
71
86
72
-
Once the operator is installed and configured, any number of namespaced `Token` and non-namespaced `ClusterToken` may be created, resulting in matching `Secret` resoures being created, containing either `token` or `username` and `password` fields, depending on configuration.
87
+
**Pod Authentication:**
73
88
74
-
The namespaced `Token` resource manages a `Secret` in the same namespace containing a fine-grained [installation access token](https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app) for the configured GitHub App, appropriate for delegated management by the namespace owner.
89
+
- **AWS**: IRSA, Pod Identity, or instance profile with above KMS permissions
90
+
- **GCP**: Workload Identity or service account with Cloud KMS access
91
+
- **Vault**: Kubernetes auth method configured with appropriate transit policy
75
92
76
-
The non-namespaced `ClusterToken` resource does the same thing, but supports abstracted management where only the managed `Secret` is bound to the configured target namespace via `.spec.secret.namespace`.
- **ClusterToken**: Centralized control with target namespace specification
101
+
- **Secrets**: Contain `token` field or `username`/`password` for HTTP Basic Auth
77
102
78
103
```yaml
79
104
apiVersion: github.as-code.io/v1
@@ -95,9 +120,9 @@ spec:
95
120
namespace: default # (required, ClusterToken-only) set the target namespace for managed `Secret`
96
121
```
97
122
98
-
#### Examples
123
+
### Examples
99
124
100
-
Manage a `Secret/github-token` containing HTTP Basic Auth `username` and `password` fields appropriate for use with a Flux' `GitRepository` [Secret Reference](https://fluxcd.io/flux/components/source/gitrepositories/#secret-reference):
125
+
**FluxCD Git Repository Access:**
101
126
102
127
```yaml
103
128
apiVersion: github.as-code.io/v1
@@ -109,12 +134,11 @@ spec:
109
134
permissions:
110
135
metadata: read
111
136
contents: read
112
-
refreshInterval: 45m
113
137
secret:
114
-
basicAuth: true
138
+
basicAuth: true# Creates username/password for Git
115
139
```
116
140
117
-
Manage a `Secret/github-status` containing a plain `token` field appropriate for use with a Flux' `Provider` [GitHub Commit Status Updates](https://fluxcd.io/flux/components/notification/providers/#github):
141
+
**GitHub API Status Updates:**
118
142
119
143
```yaml
120
144
apiVersion: github.as-code.io/v1
@@ -126,77 +150,27 @@ spec:
126
150
permissions:
127
151
metadata: read
128
152
statuses: write
129
-
refreshInterval: 45m
130
153
```
131
154
132
-
Manage `Secret/github` in the `default` namespace containing a plain `token` field, inheriting all permissions assigned to the configured GitHub App:
155
+
## Development
133
156
134
-
```yaml
135
-
apiVersion: github.as-code.io/v1
136
-
kind: ClusterToken
137
-
metadata:
138
-
name: default-github
139
-
spec:
140
-
secret:
141
-
name: github
142
-
namespace: default
143
-
```
144
-
145
-
## Contributing
146
-
147
-
All contributions from the community are welcome.
148
-
149
-
**NOTE:** Run `make help` for more information on all potential `make` targets
150
-
151
-
More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html)
152
-
153
-
### To Deploy on the cluster
154
-
155
-
156
-
#### Build and push your image to the location specified by `IMG`:
157
-
158
-
```sh
159
-
make ko-build IMG=<some-registry>/github-token-manager:tag
160
-
```
157
+
```bash
158
+
# Build and test
159
+
make build test lint
161
160
162
-
**NOTE:** This image ought to be published in the personal registry you specified.
163
-
And it is required to have access to pull the image from the working environment.
164
-
Make sure you have the proper permission to the registry if the above commands don’t work.
161
+
# Deploy locally
162
+
make ko-build IMG=<registry>/github-token-manager:tag
163
+
make deploy IMG=<registry>/github-token-manager:tag
165
164
166
-
#### Install the CRDs into the cluster:
167
-
168
-
```sh
169
-
make install
170
-
```
171
-
172
-
#### Deploy the Manager to the cluster with the image specified by `IMG`:
173
-
174
-
```sh
175
-
make deploy IMG=<some-registry>/github-token-manager:tag
165
+
# Clean up
166
+
make undeploy uninstall
176
167
```
177
168
178
-
> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin
179
-
privileges or be logged in as admin.
169
+
Run `make help` for all available targets. See [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) for details.
180
170
181
-
### To Uninstall
182
-
183
-
#### Delete the instances (CRs) from the cluster
184
-
185
-
```sh
186
-
kubectl delete -k config/samples/
187
-
```
188
-
189
-
#### Delete the APIs(CRDs) from the cluster
190
-
191
-
```sh
192
-
make uninstall
193
-
```
194
-
195
-
#### UnDeploy the controller from the cluster
171
+
## Contributing
196
172
197
-
```sh
198
-
make undeploy
199
-
```
173
+
Contributions are welcome! Please submit pull requests via GitHub. For major changes, please open an issue first to discuss your proposed changes.
0 commit comments