Skip to content

Commit

Permalink
feat!: support external KMS to secure GitHub App credentials
Browse files Browse the repository at this point in the history
* Add support for external KMS to secure private keys:
  - AWS KMS,
  - GCP KMS,
  - HashiCorp Vault.
  When using external KMS, the private key is stored in the KMS and all
  JWT signing operations are performed using the KMS API.

* Refactor configuration to better align with support for external KMS.
  Configuration secret, file name and keys are updated to better reflect
  the new functionality.

* Support full configuration via environment (best with KMS providers).

* Re-enable HTTP2 by default.

* Update Operator-SDK and dependencies to latest versions.
  • Loading branch information
isometry committed Oct 14, 2024
1 parent 03d3e4f commit 8c69a1d
Show file tree
Hide file tree
Showing 27 changed files with 1,178 additions and 1,017 deletions.
5 changes: 2 additions & 3 deletions .ko.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
---
defaultPlatforms:
- linux/arm64
- linux/amd64
- linux/s390x
- linux/ppc64le

builds:
- id: manager
main: ./cmd
main: ./cmd/manager
env:
- CGO_ENABLED=0
flags:
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ COPY internal/controller/ internal/controller/
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager ./cmd/manager

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
Expand Down
16 changes: 8 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ endif

# Set the Operator SDK version to use. By default, what is installed on the system is used.
# This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit.
OPERATOR_SDK_VERSION ?= v1.34.1
OPERATOR_SDK_VERSION ?= v1.37.0

# Image URL to use all building/pushing image targets
IMG ?= $(IMAGE_TAG_BASE):latest
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.28.3
ENVTEST_K8S_VERSION = 1.31.0

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
Expand Down Expand Up @@ -134,7 +134,7 @@ test-e2e:
go test ./test/e2e/ -v -ginkgo.v

GOLANGCI_LINT = $(shell pwd)/bin/golangci-lint
GOLANGCI_LINT_VERSION ?= v1.54.2
GOLANGCI_LINT_VERSION ?= v1.61.0
golangci-lint:
@[ -f $(GOLANGCI_LINT) ] || { \
set -e ;\
Expand All @@ -153,11 +153,11 @@ lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes

.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
go build -o bin/manager cmd/main.go
go build -o bin/manager ./cmd/manager

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./cmd/main.go
go run ./cmd/manager

# If you wish to build the manager image targeting other platforms you can use the --platform flag.
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
Expand Down Expand Up @@ -190,7 +190,7 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform
.PHONY: ko-build
ko-build: ## Build the manager image using ko.
KO_DOCKER_REPO=$(IMAGE_TAG_BASE) \
ko build --bare --platform=$(PLATFORMS) --image-label org.opencontainers.image.source=$(IMAGE_SOURCE) --push ./cmd
ko build --bare --platform=$(PLATFORMS) --image-label org.opencontainers.image.source=$(IMAGE_SOURCE) --push ./cmd/manager


##@ Deployment
Expand Down Expand Up @@ -230,8 +230,8 @@ CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest

## Tool Versions
KUSTOMIZE_VERSION ?= v5.3.0
CONTROLLER_TOOLS_VERSION ?= v0.14.0
KUSTOMIZE_VERSION ?= v5.5.0
CONTROLLER_TOOLS_VERSION ?= v0.16.4

.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading.
Expand Down
23 changes: 13 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,26 @@ This operator functions similarly to cert-manager, but instead of managing certi
* A Kubernetes cluster (v1.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`.

#### Example `github-app-credentials` secret
#### Example `gtm-config` secret
<details>
<summary><i>expand me! ✨</i></summary>

```yaml
apiVersion: v1
kind: Secret
metadata:
name: github-app-credentials
namespace: default
data:
github-token-manager.yaml: |
##### BASE64 ENCODED #####
appID: "<app-id>"
installationID: "<installation-id>"
privateKey: |
----- <BEGIN RSA PRIVATE KEY> -----
name: gtm-config
namespace: github-token-manager
stringData:
gtm.yaml: |
app_id: <app-id>
installation_id: <installation-id>
provider: file
key: /config/private.key
private.key: |
-----BEGIN RSA PRIVATE KEY-----
...elided...
-----END RSA PRIVATE KEY-----
```
</details>
Expand Down
2 changes: 1 addition & 1 deletion api/v1/clustertoken_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package v1
import (
"time"

"github.com/google/go-github/v62/github"
"github.com/google/go-github/v66/github"
"github.com/isometry/github-token-manager/internal/ghapp"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down
2 changes: 1 addition & 1 deletion api/v1/permissions.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package v1

import (
"github.com/google/go-github/v62/github"
"github.com/google/go-github/v66/github"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down
2 changes: 1 addition & 1 deletion api/v1/token_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package v1
import (
"time"

"github.com/google/go-github/v62/github"
"github.com/google/go-github/v66/github"
"github.com/isometry/github-token-manager/internal/ghapp"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down
26 changes: 10 additions & 16 deletions cmd/main.go → cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,16 @@ func main() {
var enableLeaderElection bool
var probeAddr string
var secureMetrics bool
var enableHTTP2 bool
var disableHTTP2 bool
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
flag.BoolVar(&secureMetrics, "metrics-secure", false,
"If set the metrics endpoint is served securely")
flag.BoolVar(&enableHTTP2, "enable-http2", false,
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
flag.BoolVar(&disableHTTP2, "disable-http2", false,
"If set, HTTP/2 will be disabled for the metrics and webhook servers")
opts := zap.Options{
Development: true,
}
Expand All @@ -74,20 +74,14 @@ func main() {

ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

// if the enable-http2 flag is false (the default), http/2 should be disabled
// due to its vulnerabilities. More specifically, disabling http/2 will
// prevent from being vulnerable to the HTTP/2 Stream Cancelation and
// Rapid Reset CVEs. For more information see:
// - https://github.com/advisories/GHSA-qppj-fm5r-hxr3
// - https://github.com/advisories/GHSA-4374-p667-p6c8
disableHTTP2 := func(c *tls.Config) {
setupLog.Info("disabling http/2")
c.NextProtos = []string{"http/1.1"}
}

tlsOpts := []func(*tls.Config){}
if !enableHTTP2 {
tlsOpts = append(tlsOpts, disableHTTP2)

if disableHTTP2 {
forceHTTP11 := func(c *tls.Config) {
setupLog.Info("disabling http/2")
c.NextProtos = []string{"http/1.1"}
}
tlsOpts = append(tlsOpts, forceHTTP11)
}

webhookServer := webhook.NewServer(webhook.Options{
Expand Down
Loading

0 comments on commit 8c69a1d

Please sign in to comment.