Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,44 @@ name: Docker
on:
- pull_request
- push
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
docker:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: docker/setup-qemu-action@v3
- uses: docker/metadata-action@v5
- uses: docker/metadata-action@v6
id: docker-meta
with:
images: cloudflare/lockbox
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
- uses: docker/setup-buildx-action@v4
- uses: sigstore/cosign-installer@v4.1.1
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
- uses: docker/login-action@v4
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- uses: docker/build-push-action@v5
- uses: docker/build-push-action@v7
id: docker-push
with:
file: ./cmd/lockbox-controller/Dockerfile
platforms: linux/amd64, linux/arm64
platforms: "linux/amd64,linux/arm64"
sbom: true
tags: ${{ steps.docker-meta.outputs.tags }}
labels: ${{ steps.docker-meta.outputs.labels }}
push: ${{ startsWith(github.ref, 'refs/tags/v') }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
- name: Sign Images
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
env:
TAGS: ${{ steps.docker-meta.outputs.tags }}
DIGEST: ${{ steps.docker-push.outputs.digest }}
run: echo "${TAGS}" | xargs -I {} cosign sign --yes --recursive {}@${DIGEST}
32 changes: 19 additions & 13 deletions .github/workflows/semgrep.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
name: Semgrep OSS scan
on:
pull_request: {}
workflow_dispatch: {}
pull_request: {}
push:
branches:
- trunk
schedule:
- cron: "0 0 * * *"
name: Semgrep config
- cron: "0 0 20 * *"
concurrency:
group: semgrep-${{ github.event_name }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
semgrep:
name: semgrep/ci
name: semgrep-oss
runs-on: ubuntu-latest
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
SEMGREP_URL: https://cloudflare.semgrep.dev
SEMGREP_APP_URL: https://cloudflare.semgrep.dev
SEMGREP_VERSION_CHECK_URL: https://cloudflare.semgrep.dev/api/check-version
container:
image: semgrep/semgrep
steps:
- uses: actions/checkout@v4
- run: semgrep ci
- uses: actions/checkout@v6
with:
fetch-depth: 1
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: "3.x"
- uses: geomys/sandboxed-step@v1.2.2
with:
run: pipx run semgrep==1.160.0 scan --config=auto
86 changes: 59 additions & 27 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
@@ -1,39 +1,71 @@
name: Test
on:
- pull_request
- push
push: {}
pull_request: {}
schedule:
- cron: "10 14 * * *"
workflow_dispatch: {}
permissions:
contents: read
jobs:
unit:
test:
runs-on: ubuntu-latest
name: "Go ${{ matrix.go }} Test"
strategy:
fail-fast: true
matrix:
deps:
- locked
- latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
- uses: actions/checkout@v6
with:
go-version: "stable"
- run: make test
lint:
persist-credentials: false
- uses: actions/setup-go@v6
with:
go-version: stable
- uses: geomys/sandboxed-step@v1.2.2
continue-on-error: ${{ matrix.deps == 'latest' && github.event_name != 'schedule' }}
with:
run: |
if [ "${{ matrix.deps }}" = "latest" ]; then
go get -u -t ./...
fi
go test ./...
integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
- uses: actions/checkout@v6
with:
go-version: "stable"
- uses: dominikh/staticcheck-action@v1
persist-credentials: false
- uses: actions/setup-go@v6
with:
build-tags: suite
install-go: false
integration:
needs:
- unit
- lint
go-version: stable
- uses: geomys/sandboxed-step@v1.2.2
with:
run: |
source <(go run sigs.k8s.io/controller-runtime/tools/setup-envtest@latest use -p env)
make test
staticcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: "stable"
- run: |
go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
source <(setup-envtest use -p env)
go test ./... -tags suite
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-go@v6
with:
go-version: stable
- uses: geomys/sandboxed-step@v1.2.2
with:
run: go run honnef.co/go/tools/cmd/staticcheck@latest ./...
govulncheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-go@v6
with:
go-version: stable
- uses: geomys/sandboxed-step@v1.2.2
with:
run: go run golang.org/x/vuln/cmd/govulncheck@latest ./...
11 changes: 8 additions & 3 deletions cmd/lockbox-controller/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
FROM docker.io/library/golang:1.21.5-bookworm AS builder
FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx:1.9.0 AS xx
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.27.1-trixie AS builder
COPY --from=xx / /
ARG TARGETPLATFORM
WORKDIR /go/src/app
ADD . /go/src/app

RUN apt-get update && apt-get install -y clang lld && xx-apt-get install -y xx-c-essentials
RUN xx-go --wrap
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
--mount=type=secret,id=certificates,target=/etc/ssl/certs/ca-certificates.crt \
make bin/lockbox-controller
RUN xx-verify bin/lockbox-controller && go version -m bin/lockbox-controller


FROM gcr.io/distroless/base-nossl-debian12:nonroot
FROM docker.io/chainguard/glibc-dynamic:latest
COPY --from=builder /go/src/app/bin/lockbox-controller /bin
ENTRYPOINT ["/bin/lockbox-controller"]
75 changes: 18 additions & 57 deletions cmd/lockbox-controller/main.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package main

import (
"context"
"flag"
"fmt"
"net"
"net/http"
"os"
"runtime"
Expand All @@ -20,17 +18,15 @@ import (
"github.com/rs/zerolog"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
"sigs.k8s.io/controller-runtime/pkg/metrics"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
)

var (
Expand Down Expand Up @@ -68,7 +64,7 @@ func main() {
logger.Fatal().Err(err).Str("path", keypairPath.Value).Msg("unable to parse keypair")
os.Exit(1)
}
keypair.Close()
_ = keypair.Close()

err = lockboxv1.AddToScheme(scheme.Scheme)
if err != nil {
Expand Down Expand Up @@ -98,7 +94,7 @@ func main() {
os.Exit(1)
}

recorder := mgr.GetEventRecorderFor("lockbox")
recorder := mgr.GetEventRecorder("lockbox")
client := mgr.GetClient()

sr := lockboxcontroller.NewSecretReconciler(pubKey, priKey, lockboxcontroller.WithRecorder(recorder), lockboxcontroller.WithClient(client))
Expand Down Expand Up @@ -130,66 +126,31 @@ func main() {
metrics.Registry.MustRegister(info, created, resourceVersion, lbType, labels, peerKey)

mh := statemetrics.NewStateMetricProxy(
&handler.EnqueueRequestForObject{},
info, created, resourceVersion,
lbType, peerKey, labels,
)

c, err := controller.New("lockbox-controller", mgr, controller.Options{
Reconciler: reconcile.AsReconciler(mgr.GetClient(), sr),
})

if err != nil {
logger.Fatal().Err(err).Msg("unable to create controller")
os.Exit(1)
}

if err := c.Watch(source.Kind(mgr.GetCache(), &lockboxv1.Lockbox{}), mh); err != nil {
logger.Fatal().Err(err).Msg("unable to watch Lockbox resources")
os.Exit(1)
}

if err := c.Watch(source.Kind(mgr.GetCache(), &corev1.Secret{}), handler.EnqueueRequestForOwner(scheme.Scheme, mgr.GetRESTMapper(), &lockboxv1.Lockbox{}, handler.OnlyControllerOwner())); err != nil {
logger.Fatal().Err(err).Msg("unable to watch Secret resources")
os.Exit(1)
if err := builder.ControllerManagedBy(mgr).
For(&lockboxv1.Lockbox{}).
Owns(&corev1.Secret{}).
Watches(&lockboxv1.Lockbox{}, mh).
Complete(reconcile.AsReconciler(mgr.GetClient(), sr)); err != nil {
logger.Fatal().Err(err).Send()
}

// TODO(terin): make server implement Runnable
if err := mgr.Add(manager.RunnableFunc(func(ctx context.Context) error {
mux := http.NewServeMux()
mux.Handle("/v1/public", server.PublicKey(pubKey))

ln, err := net.Listen("tcp", httpAddr.Text)
if err != nil {
return err
}

// sig.kubernetes.io/controller-runtime/pkg/internal/httpserver
s := http.Server{
mux := http.NewServeMux()
mux.Handle("GET /v1/public", server.PublicKey(pubKey))
if err := mgr.Add(&manager.Server{
Name: "keyserver",
Server: &http.Server{
Handler: mux,
Addr: httpAddr.Text,
MaxHeaderBytes: 1 << 20,
IdleTimeout: 90 * time.Second,
ReadHeaderTimeout: 32 * time.Second,
}

idleConnsClosed := make(chan struct{})
go func() {
<-ctx.Done()

if err := s.Shutdown(context.Background()); err != nil {
logger.Err(err).Send()
}
close(idleConnsClosed)
}()

if err := s.Serve(ln); err != nil && err != http.ErrServerClosed {
return err
}

<-idleConnsClosed
return nil
})); err != nil {
logger.Fatal().Err(err).Msg("unable to add server runnable")
},
}); err != nil {
logger.Fatal().Err(err).Send()
}

if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/lockbox-keypair/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ func main() {
pub64 := base64.StdEncoding.EncodeToString(lockboxPubKey[:])
pri64 := base64.StdEncoding.EncodeToString(lockboxPriKey[:])

fmt.Fprintf(os.Stdout, "public: %s\nprivate: %s\n", pub64, pri64)
_, _ = fmt.Fprintf(os.Stdout, "public: %s\nprivate: %s\n", pub64, pri64)
}
Loading
Loading