Skip to content

Commit

Permalink
feat: implement proof-of-concept
Browse files Browse the repository at this point in the history
  • Loading branch information
0x416e746f6e committed Apr 24, 2024
1 parent 7fa5aed commit ac29c51
Show file tree
Hide file tree
Showing 33 changed files with 1,746 additions and 0 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: release

on:
workflow_dispatch:
push:
tags:
- "v*"

jobs:
release:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4

- name: setup go dependencies
uses: actions/setup-go@v5
with:
go-version: "1.22"

- name: setup quemu
uses: docker/setup-qemu-action@v3

- name: setup docker buildx
uses: docker/setup-buildx-action@v3

- name: login to docker hub
uses: docker/login-action@v2
with:
username: ${{ secrets.FLASHBOTS_DOCKERHUB_USERNAME }}
password: ${{ secrets.FLASHBOTS_DOCKERHUB_TOKEN }}

- name: login to ghcr
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: build and publish backend release
uses: goreleaser/goreleaser-action@v5
with:
args: release --clean
distribution: goreleaser
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
56 changes: 56 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
env:
- CGO_ENABLED=0

builds:
- main: ./cmd
ldflags:
- -s
- -w
- -X main.version={{ .Version }}
targets:
- linux_amd64
- linux_arm64

archives:
- id: zip
format: zip
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}"
files:
- none*

checksum:
name_template: 'checksums.txt'

release:
prerelease: auto

dockers:
- dockerfile: Dockerfile.goreleaser
goarch: amd64
goos: linux
use: buildx
build_flag_templates:
- --platform=linux/amd64
image_templates:
- "flashbots/kube-sidecar-injector:{{ .Tag }}-amd64"
- "ghcr.io/flashbots/kube-sidecar-injector:{{ .Tag }}-amd64"

- dockerfile: Dockerfile.goreleaser
goarch: arm64
goos: linux
use: buildx
build_flag_templates:
- --platform=linux/arm64
image_templates:
- "flashbots/kube-sidecar-injector:{{ .Tag }}-arm64"
- "ghcr.io/flashbots/kube-sidecar-injector:{{ .Tag }}-arm64"

docker_manifests:
- name_template: "flashbots/kube-sidecar-injector:{{ .Tag }}"
image_templates:
- "flashbots/kube-sidecar-injector:{{ .Tag }}-amd64"
- "flashbots/kube-sidecar-injector:{{ .Tag }}-arm64"
- name_template: "ghcr.io/flashbots/kube-sidecar-injector:{{ .Tag }}"
image_templates:
- "ghcr.io/flashbots/kube-sidecar-injector:{{ .Tag }}-amd64"
- "ghcr.io/flashbots/kube-sidecar-injector:{{ .Tag }}-arm64"
34 changes: 34 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# stage: build ---------------------------------------------------------

FROM golang:1.22-alpine as build

RUN apk add --no-cache gcc musl-dev linux-headers

WORKDIR /go/src/github.com/flashbots/kube-sidecar-injector

COPY go.* ./
RUN go mod download

COPY . .

ARG VERSION

RUN --mount=type=cache,target=/root/.cache/go-build \
go build \
-o bin/kube-sidecar-injector \
-ldflags "-s -w -X main.version=${VERSION}" \
github.com/flashbots/kube-sidecar-injector/cmd

# stage: run -----------------------------------------------------------

# TODO: change for distroless

FROM alpine

RUN apk add --no-cache ca-certificates

WORKDIR /app

COPY --from=build /go/src/github.com/flashbots/kube-sidecar-injector/bin/kube-sidecar-injector ./kube-sidecar-injector

ENTRYPOINT ["/app/kube-sidecar-injector"]
9 changes: 9 additions & 0 deletions Dockerfile.goreleaser
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# stage: run

FROM gcr.io/distroless/static-debian12 as runner

WORKDIR /app

COPY kube-sidecar-injector ./

ENTRYPOINT [ "./kube-sidecar-injector" ]
29 changes: 29 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
VERSION := $(shell git describe --tags --always --dirty="-dev" --match "v*.*.*" || echo "development" )
VERSION := $(VERSION:v%=%)

.PHONY: build
build:
@CGO_ENABLED=0 go build \
-ldflags "-X main.version=${VERSION}" \
-o ./bin/kube-sidecar-injector \
github.com/flashbots/kube-sidecar-injector/cmd

.PHONY: snapshot
snapshot:
@goreleaser release --snapshot --clean

.PHONY: image
image:
@docker build \
--build-arg VERSION=${VERSION} \
--tag kube-sidecar-injector:${VERSION} \
.

.PHONY: deploy
deploy:
@kubectl \
--context orbstack \
apply \
--filename deploy/cluster-role.yaml \
--filename deploy/dummy.yaml \
--filename deploy/deployment.yaml
Empty file added bin/.gitkeep
Empty file.
22 changes: 22 additions & 0 deletions cert/cert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cert

import (
"crypto/tls"
"errors"
)

type Bundle struct {
CA []byte
Pair *tls.Certificate
}

type Source interface {
NewBundle() (*Bundle, error)
}

var (
ErrFailedToGenerateCert = errors.New("failed to generate certificate")
ErrFailedToGeneratePrivateKey = errors.New("failed to generate new private key")
ErrFailedToRegenerateCA = errors.New("failed to (re-)generate ca")
ErrUnspecifiedHosts = errors.New("no hosts specified for the certificate")
)
170 changes: 170 additions & 0 deletions cert/self_signer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package cert

import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"net"
"time"
)

type selfSigner struct {
organisation string
hosts []string

serial *big.Int

caCert []byte
caTemplate *x509.Certificate
caSigner crypto.Signer
}

func NewSelfSigner(organisation string, hosts []string) (Source, error) {
if len(hosts) == 0 {
return nil, ErrUnspecifiedHosts
}

serial, err := rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(128), nil))
if err != nil {
return nil, err
}

return &selfSigner{
organisation: organisation,
hosts: hosts,

serial: serial,
}, nil
}

func (s *selfSigner) NewBundle() (*Bundle, error) {
if s.caCert == nil {
if err := s.regenerateCA(); err != nil {
return nil, err
}
}

cert, err := s.generateCert()
if err != nil {
return nil, err
}

return &Bundle{
CA: bytes.Clone(s.caCert),
Pair: cert,
}, nil
}

func (s *selfSigner) newEcPrivateKey() (string, crypto.Signer, error) {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return "", nil, fmt.Errorf("%w: %w", ErrFailedToGeneratePrivateKey, err)
}

bts, err := x509.MarshalECPrivateKey(key)
if err != nil {
return "", nil, fmt.Errorf("%w: %w", ErrFailedToGeneratePrivateKey, err)
}

var buf bytes.Buffer
err = pem.Encode(&buf, &pem.Block{Type: "EC PRIVATE KEY", Bytes: bts})
if err != nil {
return "", nil, fmt.Errorf("%w: %w", ErrFailedToGeneratePrivateKey, err)
}

return buf.String(), key, nil
}

func (s *selfSigner) regenerateCA() error {
recently := time.Now().AddDate(0, 0, -1).Round(time.Hour)

_, sgn, err := s.newEcPrivateKey()
if err != nil {
return fmt.Errorf("%w: %w", ErrFailedToRegenerateCA, err)
}

tpl := &x509.Certificate{
BasicConstraintsValid: true,
IsCA: true,
SerialNumber: s.serial.Add(s.serial, big.NewInt(1)),
Subject: pkix.Name{Organization: []string{s.organisation}},

KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},

NotBefore: recently,
NotAfter: recently.AddDate(1, 0, 0),
}

bts, err := x509.CreateCertificate(rand.Reader, tpl, tpl, sgn.Public(), sgn)
if err != nil {
return fmt.Errorf("%w: %w", ErrFailedToRegenerateCA, err)
}

var buf bytes.Buffer
err = pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: bts})
if err != nil {
return fmt.Errorf("%w: %w", ErrFailedToRegenerateCA, err)
}

s.caSigner = sgn
s.caCert = buf.Bytes()
s.caTemplate = tpl

return nil
}

func (s *selfSigner) generateCert() (*tls.Certificate, error) {
recently := time.Now().AddDate(0, 0, -1).Round(time.Hour)

key, sgn, err := s.newEcPrivateKey()
if err != nil {
return nil, fmt.Errorf("%w: %w", ErrFailedToGenerateCert, err)
}

cert := &x509.Certificate{
BasicConstraintsValid: true,
SerialNumber: s.serial.Add(s.serial, big.NewInt(1)),
Subject: pkix.Name{CommonName: s.hosts[0], Organization: []string{s.organisation}},

KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},

NotBefore: recently,
NotAfter: recently.AddDate(1, 0, 0),
}

for _, h := range s.hosts {
if ip := net.ParseIP(h); ip != nil {
cert.IPAddresses = append(cert.IPAddresses, ip)
} else {
cert.DNSNames = append(cert.DNSNames, h)
}
}

bts, err := x509.CreateCertificate(rand.Reader, cert, s.caTemplate, sgn.Public(), s.caSigner)
if err != nil {
return nil, fmt.Errorf("%w: %w", ErrFailedToGenerateCert, err)
}

var buf bytes.Buffer
err = pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: bts})
if err != nil {
return nil, fmt.Errorf("%w: %w", ErrFailedToGenerateCert, err)
}

pair, err := tls.X509KeyPair(buf.Bytes(), []byte(key))
if err != nil {
return nil, fmt.Errorf("%w: %w", ErrFailedToGenerateCert, err)
}

return &pair, nil
}
Loading

0 comments on commit ac29c51

Please sign in to comment.