Skip to content

Commit 04f13b2

Browse files
committed
Initial commit
0 parents  commit 04f13b2

35 files changed

Lines changed: 1974 additions & 0 deletions

.github/workflows/release.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
goreleaser:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
20+
- name: Set up Go
21+
uses: actions/setup-go@v5
22+
with:
23+
go-version: stable
24+
25+
- name: Run GoReleaser
26+
uses: goreleaser/goreleaser-action@v6
27+
with:
28+
distribution: goreleaser
29+
version: latest
30+
args: release --clean
31+
env:
32+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/test.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4
15+
16+
- name: Set up Go
17+
uses: actions/setup-go@v5
18+
with:
19+
go-version: stable
20+
21+
- name: Build
22+
run: go build -v ./...
23+
24+
- name: Test
25+
run: go test -v ./...

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
digilol-cert-pushpuller
2+
dist/
3+
*.toml
4+
!*.example.toml
5+
*.key
6+
.hashes.json
7+
.claude/

.goreleaser.yaml

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
version: 2
2+
3+
builds:
4+
- env:
5+
- CGO_ENABLED=0
6+
goos:
7+
- linux
8+
- darwin
9+
- freebsd
10+
goarch:
11+
- amd64
12+
- arm64
13+
ldflags:
14+
- -s -w
15+
flags:
16+
- -trimpath
17+
18+
archives:
19+
- format: tar.gz
20+
name_template: >-
21+
{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}
22+
files:
23+
- LICENSE.txt
24+
- README.md
25+
- push.example.toml
26+
- pull.example.toml
27+
28+
checksum:
29+
name_template: "checksums.txt"
30+
31+
nfpms:
32+
- package_name: digilol-cert-pushpuller
33+
maintainer: Laurynas Četyrkinas <laurynas@digilol.net>
34+
description: Tool for encrypting and syncing certificates via S3 with automatic renewal
35+
license: Apache-2.0
36+
formats:
37+
- deb
38+
- rpm
39+
- apk
40+
overrides:
41+
deb:
42+
scripts:
43+
postinstall: packaging/scripts/deb/postinst
44+
preremove: packaging/scripts/deb/prerm
45+
postremove: packaging/scripts/deb/postrm
46+
rpm:
47+
scripts:
48+
postinstall: packaging/scripts/rpm/postinst
49+
preremove: packaging/scripts/rpm/prerm
50+
postremove: packaging/scripts/rpm/postrm
51+
apk:
52+
scripts:
53+
preremove: packaging/scripts/apk/pre-deinstall
54+
contents:
55+
- src: packaging/systemd/digilol-cert-pushpuller-push.service
56+
dst: /usr/lib/systemd/system/digilol-cert-pushpuller-push.service
57+
packager: deb
58+
- src: packaging/systemd/digilol-cert-pushpuller-push.service
59+
dst: /usr/lib/systemd/system/digilol-cert-pushpuller-push.service
60+
packager: rpm
61+
- src: packaging/systemd/digilol-cert-pushpuller-push.timer
62+
dst: /usr/lib/systemd/system/digilol-cert-pushpuller-push.timer
63+
packager: deb
64+
- src: packaging/systemd/digilol-cert-pushpuller-push.timer
65+
dst: /usr/lib/systemd/system/digilol-cert-pushpuller-push.timer
66+
packager: rpm
67+
- src: packaging/systemd/digilol-cert-pushpuller-pull.service
68+
dst: /usr/lib/systemd/system/digilol-cert-pushpuller-pull.service
69+
packager: deb
70+
- src: packaging/systemd/digilol-cert-pushpuller-pull.service
71+
dst: /usr/lib/systemd/system/digilol-cert-pushpuller-pull.service
72+
packager: rpm
73+
- src: packaging/systemd/digilol-cert-pushpuller-pull.timer
74+
dst: /usr/lib/systemd/system/digilol-cert-pushpuller-pull.timer
75+
packager: deb
76+
- src: packaging/systemd/digilol-cert-pushpuller-pull.timer
77+
dst: /usr/lib/systemd/system/digilol-cert-pushpuller-pull.timer
78+
packager: rpm
79+
- src: packaging/openrc/digilol-cert-pushpuller-push
80+
dst: /etc/init.d/digilol-cert-pushpuller-push
81+
file_info:
82+
mode: 0755
83+
packager: apk
84+
- src: packaging/openrc/digilol-cert-pushpuller-pull
85+
dst: /etc/init.d/digilol-cert-pushpuller-pull
86+
file_info:
87+
mode: 0755
88+
packager: apk
89+
- src: push.example.toml
90+
dst: /usr/share/doc/digilol-cert-pushpuller/push.example.toml
91+
- src: pull.example.toml
92+
dst: /usr/share/doc/digilol-cert-pushpuller/pull.example.toml
93+
- dst: /etc/digilol-cert-pushpuller
94+
type: dir
95+
- dst: /var/lib/digilol-cert-pushpuller/keys
96+
type: dir
97+
file_info:
98+
mode: 0700
99+
- dst: /var/lib/digilol-cert-pushpuller/certificates
100+
type: dir

CLAUDE.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Overview
6+
7+
`digilol-cert-pushpuller` is a Go-based tool for encrypting and syncing TLS certificates via S3 with automatic renewal support using LEGO. It operates in two modes:
8+
9+
- **Push mode** (server): Renews certificates via LEGO, encrypts them, and uploads to S3
10+
- **Pull mode** (client): Downloads and decrypts certificates from S3
11+
12+
## Build Commands
13+
14+
```bash
15+
# Build binary
16+
go build -trimpath -ldflags="-s -w"
17+
18+
# Run tests
19+
go test ./...
20+
21+
# Run specific package tests
22+
go test ./internal/config
23+
go test ./internal/crypto
24+
go test ./internal/util
25+
26+
# Build release packages (requires goreleaser)
27+
goreleaser release --snapshot --clean
28+
```
29+
30+
## Running
31+
32+
```bash
33+
# Push certificates (server mode)
34+
./digilol-cert-pushpuller push --config /path/to/push.toml
35+
36+
# Pull certificates (client mode)
37+
./digilol-cert-pushpuller pull --config /path/to/pull.toml
38+
```
39+
40+
## Architecture
41+
42+
### Core Components
43+
44+
1. **main.go**: Entry point that parses command (`push`/`pull`) and config file, handles daemon mode with scheduling and signal handling
45+
46+
2. **push.go**: Server-side logic
47+
48+
- Executes LEGO renewal commands (push.go:40-46)
49+
- Compares local certificate SHA256 hashes with `.hashes.json` from S3 (push.go:54-73)
50+
- Encrypts changed certificates per-domain using keys from `key_dir` (push.go:106-146)
51+
- Uploads encrypted `.enc` files to S3 and updates `.hashes.json` (push.go:148-179)
52+
- Runs reload command (e.g., `systemctl reload nginx`) (push.go:182-187)
53+
54+
3. **pull.go**: Client-side logic
55+
- Downloads `.hashes.json` from S3 (pull.go:44-63)
56+
- Lists all `.enc` files in S3 bucket (pull.go:76-94)
57+
- For each file: checks if local hash matches S3 hash to skip unchanged files (pull.go:128-139)
58+
- Downloads and decrypts only changed files using matching `.key` files (pull.go:142-167)
59+
- Runs reload command (pull.go:171-176)
60+
61+
### Internal Packages
62+
63+
- **internal/config**: TOML configuration parsing and encryption key management
64+
65+
- `LoadPush()`/`LoadPull()`: Parse TOML configs
66+
- `GetOrCreateKey()`: Per-certificate key management (generates 32-byte keys, stored as base64 in `.key` files with 0600 permissions)
67+
- Key files named `{certname}.key` (e.g., `_.example.com.key`)
68+
69+
- **internal/crypto**: ChaCha20-Poly1305 encryption using `github.com/minio/sio`
70+
71+
- `EncryptData()`: Encrypts certificate data
72+
- `DecryptData()`: Decrypts certificate data
73+
74+
- **internal/s3util**: AWS S3 client creation
75+
76+
- `NewClient()`: Creates S3 client with custom endpoint support for S3-compatible services
77+
78+
- **internal/util**: Shell command execution
79+
- `RunCommandWithEnv()`: Executes LEGO commands and reload commands with custom environment variables
80+
81+
### Security Model
82+
83+
**Per-certificate encryption**: Each certificate domain (e.g., `_.example.com`) has its own 256-bit encryption key. This allows selective access control - clients can only decrypt certificates for which they possess the corresponding `.key` file. The server (push) generates keys automatically if they don't exist. Clients (pull) must have the key files distributed separately to decrypt certificates.
84+
85+
### Configuration
86+
87+
- See `push.example.toml` and `pull.example.toml` for complete examples
88+
- Default config location: `/etc/digilol-cert-pushpuller/{push,pull}.toml`
89+
- Supports S3-compatible services via `endpoint` and `force_path_style` options
90+
- Daemon mode available for systems without systemd timers (e.g., Alpine Linux)
91+
92+
### Deployment
93+
94+
Uses GoReleaser (`.goreleaser.yaml`) to build:
95+
96+
- Binaries for Linux/Darwin/FreeBSD (amd64, arm64)
97+
- DEB packages (Debian/Ubuntu) with systemd units
98+
- RPM packages (RHEL/Fedora) with systemd units
99+
- APK packages (Alpine) with OpenRC scripts
100+
101+
Systemd timers and OpenRC scripts are in `packaging/` directory.

0 commit comments

Comments
 (0)