Compare commits

..

31 commits
0.2.0 ... main

Author SHA1 Message Date
0cea3f282b
set disableExplicitIndexURLs
All checks were successful
ci/woodpecker/push/deploy-docs Pipeline was successful
2024-07-31 15:34:25 +02:00
527c038f02
update docs
All checks were successful
ci/woodpecker/push/deploy-docs Pipeline was successful
2024-07-30 14:09:53 +02:00
7098a6c5eb
update Docs with latest version
All checks were successful
ci/woodpecker/push/deploy-docs Pipeline was successful
2024-07-30 09:01:42 +02:00
3a0a739fae
add git as dependency to CI pipeline
All checks were successful
ci/woodpecker/tag/build-and-deploy/3 Pipeline was successful
ci/woodpecker/tag/build-and-deploy/2 Pipeline was successful
ci/woodpecker/tag/build-and-deploy/1 Pipeline was successful
2024-07-30 08:57:48 +02:00
146a2800cb
minor docs change
All checks were successful
ci/woodpecker/push/deploy-docs Pipeline was successful
ci/woodpecker/tag/build-and-deploy/2 Pipeline was successful
ci/woodpecker/tag/build-and-deploy/1 Pipeline was successful
ci/woodpecker/tag/build-and-deploy/3 Pipeline was successful
2024-07-30 08:54:08 +02:00
20cbb33778 Merge pull request 'add Makefile for easier builds' (#3) from feature-makefile into main
Reviewed-on: #3
2024-07-30 08:53:09 +02:00
6f20779714
bump version to 0.2.2 2024-07-30 08:49:00 +02:00
b8ec72877d
update CI 2024-07-30 08:48:48 +02:00
05a536a17d
add makefile 2024-07-30 08:42:51 +02:00
8d4f92f7be Merge pull request 'Change Docs theme to relearn' (#2) from feature-new-docs into main
All checks were successful
ci/woodpecker/push/deploy-docs Pipeline was successful
Reviewed-on: #2
2024-07-30 08:28:16 +02:00
eb367df0f9
add favicon and page logo 2024-07-30 08:27:49 +02:00
abc1ef0a79
describe configuration options 2024-07-30 08:11:08 +02:00
2fe2b980be
enable search feature 2024-07-29 20:30:56 +02:00
f40bdd5cbf
describe installation process 2024-07-29 20:30:42 +02:00
fcdc147dd2
small wording changes 2024-07-29 20:30:09 +02:00
74c32b87b9
begin installation page 2024-07-29 12:47:08 +02:00
dd104386a7
add sidbar items 2024-07-29 12:46:57 +02:00
5c80f88608
change to relearn theme 2024-07-28 17:58:52 +02:00
e46d924907
update contribution documenation
All checks were successful
ci/woodpecker/push/deploy-docs Pipeline was successful
2024-07-28 14:36:06 +02:00
345b2b10f7
clean up old docs
All checks were successful
ci/woodpecker/push/deploy-docs Pipeline was successful
2024-07-28 14:28:21 +02:00
6c2b04e6b9
update quickstart docs
All checks were successful
ci/woodpecker/push/deploy-docs Pipeline was successful
2024-07-28 08:11:49 +02:00
b988e4cf51
refactor logger init function 2024-07-12 17:41:50 +02:00
60aea576dc
remove sentry remnants 2024-07-12 17:31:44 +02:00
5e0e263ff8
use dev mail
All checks were successful
ci/woodpecker/push/deploy-docs Pipeline was successful
2024-07-12 14:37:05 +02:00
08cb6e27bc
update readme 2024-07-12 14:31:47 +02:00
9ee54b6c2a
add header
All checks were successful
ci/woodpecker/push/deploy-docs Pipeline was successful
2024-07-12 13:07:50 +02:00
5a6e51463a
add docs to repo 2024-07-12 13:04:33 +02:00
99c5a497f0
add vscode debug config 2024-07-12 12:54:25 +02:00
4997114458
bump version to 0.2.1
All checks were successful
ci/woodpecker/tag/build-and-deploy/3 Pipeline was successful
ci/woodpecker/tag/build-and-deploy/2 Pipeline was successful
ci/woodpecker/tag/build-and-deploy/1 Pipeline was successful
2024-07-12 11:18:50 +02:00
d1ac68c4f7
fix configuration validation 2024-07-12 11:18:32 +02:00
1746653453
update example config file 2024-07-12 10:58:27 +02:00
34 changed files with 573 additions and 89 deletions

41
.gitignore vendored
View file

@ -1,31 +1,28 @@
# ---> Go
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
# Allowlisting gitignore template for GO projects prevents us
# from adding various unwanted local files, such as generated
# files, developer configurations or IDE-specific files etc.
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Recommended: Go.AllowList.gitignore
# Test binary, built with `go test -c`
*.test
# Ignore everything
*
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# But not these files...
!/.gitignore
# Dependency directories (remove the comment below to include it)
# vendor/
!*.go
!go.sum
!go.mod
# Go workspace file
go.work
!examples/*
bin/
!*.md
!LICENSE
examples/testing/
!Makefile
*.yaml
!examples/*.yaml
# Woodpecker CI
!.woodpecker/*
test/
# ...even if they are in subdirectories
!*/

24
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,24 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug Dry Run",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/certwarden-deploy/main.go",
"args": ["--config", "${workspaceFolder}/config.yaml", "--dry-run"]
},
{
"name": "Debug",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/certwarden-deploy/main.go",
"args": ["--config", "${workspaceFolder}/config.yaml", "--verbose"]
}
]
}

View file

@ -20,13 +20,13 @@ steps:
- APP_NAME=certwarden-deploy
- FORGE=https://code.lila.network
commands:
- apk add --update --no-cache xz curl jq
- go mod download
- go build -o output/$APP_NAME-${CI_COMMIT_TAG##v}-${GOOS}-${GOARCH}${GOARM} main.go
- cd output
- xz --keep --compress $APP_NAME-${CI_COMMIT_TAG##v}-${GOOS}-${GOARCH}${GOARM}
- sha256sum $APP_NAME-${CI_COMMIT_TAG##v}-${GOOS}-${GOARCH}${GOARM} >> $APP_NAME-${CI_COMMIT_TAG##v}-${GOOS}-${GOARCH}${GOARM}.sha256
- sha256sum $APP_NAME-${CI_COMMIT_TAG##v}-${GOOS}-${GOARCH}${GOARM}.xz >> $APP_NAME-${CI_COMMIT_TAG##v}-${GOOS}-${GOARCH}${GOARM}.xz.sha256
- apk add --update --no-cache xz curl jq make git
- make build
- cd bin/
- mv $APP_NAME $APP_NAME-${GOOS}-${GOARCH}${GOARM}
- xz --keep --compress $APP_NAME-${GOOS}-${GOARCH}${GOARM}
- sha256sum $APP_NAME-${GOOS}-${GOARCH}${GOARM} >> $APP_NAME-${GOOS}-${GOARCH}${GOARM}.sha256
- sha256sum $APP_NAME-${GOOS}-${GOARCH}${GOARM}.xz >> $APP_NAME-${GOOS}-${GOARCH}${GOARM}.xz.sha256
- |-
export RELEASE_ID=`curl --location "$FORGE/api/v1/repos/$CI_REPO/releases?limit=10" \
--header 'Accept: application/json' -s -S \
@ -35,23 +35,23 @@ steps:
curl --location "$FORGE/api/v1/repos/$CI_REPO/releases/$RELEASE_ID/assets" \
--header "Authorization: token $FORGEJO_APIKEY" \
--header 'Content-Type: multipart/form-data' -s -S \
--form "attachment=@$APP_NAME-${CI_COMMIT_TAG##v}-${GOOS}-${GOARCH}${GOARM};type=application/octet-stream" \
--form "attachment=@$APP_NAME-${GOOS}-${GOARCH}${GOARM};type=application/octet-stream" \
--fail-with-body
- |-
curl --location "$FORGE/api/v1/repos/$CI_REPO/releases/$RELEASE_ID/assets" \
--header "Authorization: token $FORGEJO_APIKEY" \
--header 'Content-Type: multipart/form-data' -s -S \
--form "attachment=@$APP_NAME-${CI_COMMIT_TAG##v}-${GOOS}-${GOARCH}${GOARM}.xz;type=application/octet-stream" \
--form "attachment=@$APP_NAME-${GOOS}-${GOARCH}${GOARM}.xz;type=application/octet-stream" \
--fail-with-body
- |-
curl --location "$FORGE/api/v1/repos/$CI_REPO/releases/$RELEASE_ID/assets" \
--header "Authorization: token $FORGEJO_APIKEY" \
--header 'Content-Type: multipart/form-data' -s -S \
--form "attachment=@$APP_NAME-${CI_COMMIT_TAG##v}-${GOOS}-${GOARCH}${GOARM}.sha256;type=application/octet-stream" \
--form "attachment=@$APP_NAME-${GOOS}-${GOARCH}${GOARM}.sha256;type=application/octet-stream" \
--fail-with-body
- |-
curl --location "$FORGE/api/v1/repos/$CI_REPO/releases/$RELEASE_ID/assets" \
--header "Authorization: token $FORGEJO_APIKEY" \
--header 'Content-Type: multipart/form-data' -s -S \
--form "attachment=@$APP_NAME-${CI_COMMIT_TAG##v}-${GOOS}-${GOARCH}${GOARM}.xz.sha256;type=application/octet-stream" \
--form "attachment=@$APP_NAME-${GOOS}-${GOARCH}${GOARM}.xz.sha256;type=application/octet-stream" \
--fail-with-body

View file

@ -0,0 +1,38 @@
when:
- event: push
branch: main
path:
include:
- 'docs/**'
- '.woodpecker/deploy-docs.yml'
ignore_message: '[ALL]'
steps:
build:
image: golang:1.22-bookworm
environment:
- HUGO_VERSION=0.128.1
- TZ=Europe/Berlin
commands:
- cd docs/
- wget https://github.com/gohugoio/hugo/releases/download/v$${HUGO_VERSION}/hugo_extended_$${HUGO_VERSION}_linux-amd64.deb && apt install ./hugo_extended_$${HUGO_VERSION}_linux-amd64.deb && rm -f hugo_extended_$${HUGO_VERSION}_linux-amd64.deb
- hugo --minify --destination ./public
upload:
image: alpine:latest
secrets:
- RSYNC_SSHKEY
- RSYNC_TARGET_SERVER
- RSYNC_TARGET_USER
environment:
- TARGET_PATH=/webroot/certwarden-deploy.adora.codes
- RSYNC_TARGET_PORT=2003
commands:
- cd docs/
- apk add --update --no-cache openssh rsync git
- mkdir -p $HOME/.ssh
- echo "$RSYNC_SSHKEY" > $HOME/.ssh/id_ed25519
- chmod 0600 $HOME/.ssh/id_ed25519
- ssh-keyscan -t ed25519 -p $RSYNC_TARGET_PORT $RSYNC_TARGET_SERVER >> $HOME/.ssh/known_hosts
- rsync -avh -e "ssh -p $RSYNC_TARGET_PORT" --delete ./public/ $RSYNC_TARGET_USER@$RSYNC_TARGET_SERVER:$TARGET_PATH

View file

@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.2.2] - 2024-07-30
### Changed
- changed the way the version string is handled internally
- CI pipeline changed
- documentation is now more sophisticated and has a new theme
### Added
- Makefile
## [0.2.1] - 2024-07-12
### Fixed
- Configuration validation did not work as intended
### Changed
- updated example config file
## [0.2.0] - 2024-07-11
### ⚠️ Breaking Changes
@ -34,7 +50,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- some documentation
[unreleased]: https://code.lila.network/adoralaura/certwarden-deploy/compare/0.2.0...HEAD
[unreleased]: https://code.lila.network/adoralaura/certwarden-deploy/compare/0.2.2...HEAD
[0.2.2]: https://code.lila.network/adoralaura/certwarden-deploy/compare/0.2.1...0.2.2
[0.2.1]: https://code.lila.network/adoralaura/certwarden-deploy/compare/0.2.0...0.2.1
[0.2.0]: https://code.lila.network/adoralaura/certwarden-deploy/compare/0.1.1...0.2.0
[0.1.1]: https://code.lila.network/adoralaura/certwarden-deploy/compare/0.1.0...0.1.1
[0.1.0]: https://code.lila.network/adoralaura/certwarden-deploy/releases/tag/0.1.0

View file

@ -6,7 +6,7 @@ I use my own [Forgejo Instance](https://code.lila.network) to manage issues and
addressing (with `@...`) the maintainer of this repository (see
[MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request.
* If you plan to do something more involved, first please [send me a mail]( mailto:adora@lila.network?subject=%5Bcertwarden-deploy%5D).
* If you plan to do something more involved, first please [send me a mail]( mailto:dev@lauka.net?subject=%5Bcertwarden-deploy%5D).
# What to contribute

View file

@ -1 +1 @@
* Adora Laura Kalb <adora@lila.network> @adoralaura
* Adora Laura Kalb <dev@lauka.net> @adoralaura

13
Makefile Normal file
View file

@ -0,0 +1,13 @@
# Set the default Go build flags
GOFLAGS = -ldflags='-w -s -X constants.Version=$(VERSION)'
# Build the application
build:
go build $(GOFLAGS) -o bin/certwarden-deploy cmd/certwarden-deploy/main.go
# Clean the build artifacts
clean:
rm -rf bin
# Set a version for the build
VERSION := $(shell git describe --tags --always)

View file

@ -2,10 +2,81 @@
![status-badge](https://ci.lila.network/api/badges/22/status.svg)
[![Please don't upload to GitHub](https://nogithub.codeberg.page/badge.svg)](https://nogithub.codeberg.page)
This is a tool to deploy certificates from a [CertWarden](https://www.certwarden.com/) instance.
This is a simple binary to deploy certificates from a [CertWarden](https://www.certwarden.com/) instance.
## Quick Start
Installation of the required CertWarden instance is out of scope of this documentation. For detailed instructions regarding CertWarden, please visit [it's documentation](https://www.certwarden.com/docs/introduction/)
To quickly get started with `certwarden-deploy`, just download the binary...
```shell
# this downloads certwarden-deploy version 0.2.2
# to /usr/local/bin/certwarden-deploy
sudo wget https://code.lila.network/adoralaura/certwarden-deploy/releases/download/0.2.2/certwarden-deploy-linux-amd64 -O /usr/local/bin/certwarden-deploy
sudo chmod +x /usr/local/bin/certwarden-deploy
```
... fill out the config file...
```shell
vi /etc/certwarden-deploy/config.yaml
```
```yaml
# Base URL of the CertWarden instance
# required
base_url: "https://certwarden.example.com"
# Set this to true if your CertWarden instance does not have a publicly trusted
# TLS certificate (e.g. it has a self signed one)
# default is false
disable_certificate_validation: false
# define all managed certificates here
certificates:
# name is a unique identifier that must start and end with an alphanumeric character,
# and can contain the following characters: a-zA-Z0-9._-
# required
- name: test-certificate.example.com
# Contains the API-Key to fetch the certificate from the server
# required
cert_secret: examplekey_notvalid_hrzjGDDw8z
# path where to save the certificate
# required
cert_path: "/path/to/test-certificate.example.com-cert.pem"
# Contains the API-Key to fetch the private key from the server
# required
key_secret: examplekey_notvalid_hrzbbDDw8z
# path where to save the private key
# required
key_path: "/path/to/test-certificate.example.com-key.pem"
# action to run when certificate was updated or --force is on
action: "/usr/bin/systemd reload caddy"
```
... and run it!
```shell
certwarden-deploy -v
```
## Contributing
I use my own [Forgejo](https://forgejo.org/) Instance [code.lila.network](https://code.lila.network) to manage issues, pull requests and CI/CD.
* If you have a trivial fix or improvement, go ahead and send a diff to the maintainer(s) of this repository (see
[MAINTAINERS.md](https://code.lila.network/adoralaura/certwarden-deploy/src/branch/main/MAINTAINERS.md)).
* If you plan to do something more involved, first please [send me a mail]( mailto:dev@lauka.net?subject=%5Bcertwarden-deploy%5D)mso I can create an account for you.
### Non-development Contibutions
The best way to help without speaking a lot of Go would be to share your
configuration, setup, and tips. If you have something
that works and is not in the repository, please pay it forward and
share what works.
## Changelog
You can find the Changelog here: [Changelog](https://code.lila.network/adoralaura/certwarden-deploy/src/branch/main/CHANGELOG.md)
## License
`certwarden-deploy` is available under the MIT license. See the LICENSE file for more info.
`certwarden-deploy` is available under the MIT license. See the [LICENSE](https://code.lila.network/adoralaura/certwarden-deploy/src/branch/main/LICENSE) file for more info.

View file

@ -2,25 +2,20 @@
Copyright © 2024 Laura Kalb <dev@lauka.net>
The code of this project is available under the MIT license. See the LICENSE file for more info.
*/
package cmd
package main
import (
"os"
"time"
"code.lila.network/adoralaura/certwarden-deploy/internal/cli"
"code.lila.network/adoralaura/certwarden-deploy/internal/configuration"
"github.com/getsentry/sentry-go"
)
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
func main() {
err := cli.RootCmd.Execute()
if err != nil {
os.Exit(1)
}
defer sentry.Flush(2 * time.Second)
}
func init() {

15
docs/.gitignore vendored Normal file
View file

@ -0,0 +1,15 @@
# Generated files by hugo
/public/
/resources/_gen/
/assets/jsconfig.json
hugo_stats.json
# Executable may be added to repository
hugo.exe
hugo.darwin
hugo.linux
# Temporary lock file while building
/.hugo_build.lock
!**.html

9
docs/LICENSE Normal file
View file

@ -0,0 +1,9 @@
MIT License
Copyright 2024 Adora Laura Kalb <dev@lauka.net>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

1
docs/README.md Normal file
View file

@ -0,0 +1 @@
# certwarden-deploy Documentation

View file

@ -0,0 +1,5 @@
+++
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
date = {{ .Date }}
draft = true
+++

54
docs/config.toml Normal file
View file

@ -0,0 +1,54 @@
baseURL = 'https://certwarden-deploy.adora.codes/'
languageCode = 'en-us'
title = 'certwarden-deploy'
author = ""
theme = "github.com/McShelby/hugo-theme-relearn"
repo = "https://code.lila.network/adoralaura/certwarden-deploy"
enableGitInfo = true
enableRobotsTXT = true
uniqueHomePage = false # change to false to add sidebar to homepage
[params]
disableLandingPageButton = false
disableLanguageSwitchingButton = false
editURL = "https://code.lila.network/adoralaura/certwarden-deploy/_edit/main/docs/content/${FilePath}"
externalLinkTarget = "_blank"
headingPre = '<script defer src="https://esseles.adora.codes/script.js" data-website-id="fe4ec517-25b2-4e0d-b502-6bd3a7420849"></script>'
disableExplicitIndexURLs = true
[params.author]
name = 'Adora Laura Kalb'
[outputs]
home = ['html', 'rss', 'search']
[menu]
[[menu.shortcuts]]
identifier = 'ds'
name = "<i class='fa-fw fas fa-code-branch'></i> certwarden-deploy Git Repository"
url = 'https://code.lila.network/adoralaura/certwarden-deploy'
weight = 10
[[menu.shortcuts]]
name = "<i class='fa-fw fas fa-arrow-up-right-from-square'></i> CertWarden GitHub"
url = 'showcase/'
weight = 11
[[menu.shortcuts]]
identifier = 'hugodoc'
name = "<i class='fa-fw fas fa-arrow-up-right-from-square'></i> CertWarden Website"
url = 'https://gohugo.io/'
weight = 20
# [[menu.shortcuts]]
# name = "<i class='fa-fw fas fa-bullhorn'></i> Credits"
# url = 'more/credits/'
# weight = 30
#
# [[menu.shortcuts]]
# name = "<i class='fa-fw fas fa-tags'></i> Tags"
# url = 'tags/'
# weight = 40

93
docs/content/_index.md Normal file
View file

@ -0,0 +1,93 @@
---
title: CertWarden-Deploy
type: docs
---
[CertWarden](https://www.certwarden.com/) is a self-hosted Centralized ACME Certificate Management platform. With it you can manage and aquire Let's Encrypt certificates.
However, to deploy them to your hosts, for now there only was a docker client, and that was too bloated for me.
So I built `certwarden-deploy`, a dependency-less binary that can run via crontab/systemd timers and that can fetch new certificates and run actions after new certificates got rolled out.
## Quick Start
Installation of the required CertWarden instance is out of scope of this documentation. For detailed instructions regarding CertWarden, please visit [it's documentation](https://www.certwarden.com/docs/introduction/)
To quickly get started with `certwarden-deploy`, just download the binary...
```shell
# this downloads certwarden-deploy version 0.2.2
# to /usr/local/bin/certwarden-deploy
sudo wget https://code.lila.network/adoralaura/certwarden-deploy/releases/download/0.2.2/certwarden-deploy-linux-amd64 -O /usr/local/bin/certwarden-deploy
sudo chmod +x /usr/local/bin/certwarden-deploy
```
... fill out the config file...
`vi /etc/certwarden-deploy/config.yaml`
```yaml
# Base URL of the CertWarden instance
# required
base_url: "https://certwarden.example.com"
# Set this to true if your CertWarden instance does not have a publicly trusted
# TLS certificate (e.g. it has a self signed one)
# default is false
disable_certificate_validation: false
# define all managed certificates here
certificates:
# name is a unique identifier that must start and end with an alphanumeric character,
# and can contain the following characters: a-zA-Z0-9._-
# required
- name: test-certificate.example.com
# Contains the API-Key to fetch the certificate from the server
# required
cert_secret: examplekey_notvalid_hrzjGDDw8z
# path where to save the certificate
# required
cert_path: "/path/to/test-certificate.example.com-cert.pem"
# Contains the API-Key to fetch the private key from the server
# required
key_secret: examplekey_notvalid_hrzbbDDw8z
# path where to save the private key
# required
key_path: "/path/to/test-certificate.example.com-key.pem"
# action to run when certificate was updated or --force is on
action: "/usr/bin/systemd reload caddy"
```
... and run it!
```shell
certwarden-deploy -v
```
## Contributing
I use my own [Forgejo](https://forgejo.org/) Instance [code.lila.network](https://code.lila.network) to manage issues, pull requests and CI/CD.
* If you have a trivial fix or improvement, go ahead and send a diff to the maintainer(s) of this repository (see
[MAINTAINERS.md](https://code.lila.network/adoralaura/certwarden-deploy/src/branch/main/MAINTAINERS.md)).
* If you plan to do something more involved, first please [send me a mail](mailto:dev@lauka.net?subject=%5Bcertwarden-deploy%5D) so I can create an account for you.
### Non-development Contibutions
The best way to help without speaking a lot of Go would be to share your
configuration, setup, and tips. If you have something
that works and is not in the repository, please pay it forward and
share what works.
## Changelog
You can find the Changelog here: [Changelog](https://code.lila.network/adoralaura/certwarden-deploy/src/branch/main/CHANGELOG.md)
## License
`certwarden-deploy` is available under the MIT license. See the [License page](/license/) for more info.

View file

@ -0,0 +1,85 @@
---
title: Configuration
weight: 20
---
This document describes how to configure `certwarden-deploy` and which certificates should be managed by it. The configuration file uses the [YAML format](https://yaml.org/) for a human-readable and easy-to-maintain structure.
## certwarden-deploy CLI Options
```plaintext
$ ./certwarden-deploy --help
certwarden-deploy is a CLI utility to deploy certificates managed by CertWarden.
Configuration is handled by a single YAML file, so you can get started quickly.
For more information on how to configure this tool, visit the docs at https://certwarden-deploy.adora.codes
Usage:
certwarden-deploy [flags]
Flags:
-c, --config string Path to config file (default is /etc/certwarden-deploy/config.yaml) (default "/etc/certwarden-deploy/config.yaml")
-d, --dry-run Just show the would-be changes without changing the file system (turns on verbose logging)
-f, --force Force overwriting and execution action to occur, regardless if certificate already exists
-h, --help help for certwarden-deploy
-q, --quiet Disable any logging (if both -q and -v are set, quiet wins)
-v, --verbose Enable verbose logging
--version version for certwarden-deploy
```
## Configuration File Options
`base_url` (required):
This string specifies the base URL of your CertWarden instance.
`disable_certificate_validation` (optional, default: false):
This boolean flag indicates whether to disable certificate validation for the CertWarden instance. Set this to true only if your CertWarden instance uses a self-signed certificate and you trust it explicitly. **Disabling validation weakens security, so use it with caution.**
`certificates:` (required):
This is a list that defines each certificate to be managed.
Each certificate definition is a nested YAML block with the following properties:
Each certificate configuration consists of:
`name` (required):
This string is a unique identifier for the certificate and must be the same as in you CertWarden instance.
It must start and end with an alphanumeric character and can contain letters (a-zA-Z), numbers (0-9), underscore (_), hyphen (-), and period (.).
`cert_secret` (required):
This string holds the API key used to fetch the certificate data from the CertWarden server.
`cert_path` (required):
This string defines the file path where the downloaded certificate will be saved.
`key_secret` (required):
This string holds the API key used to fetch the private key data from the CertWarden server.
`key_path` (required):
This string defines the file path where the downloaded private key will be saved.
`action` (optional):
This string specifies a command to run after a certificate is updated or when the --force flag is used during execution.
The example uses a systemd reload command for the popular reverse proxy named "caddy".
Example Configuration:
```yaml
# Base URL of the CertWarden instance
base_url: "https://certwarden.example.com"
# Disable certificate validation (not recommended for production)
disable_certificate_validation: false
# Define all managed certificates here
certificates:
- name: test-certificate.example.com
cert_secret: examplekey_notvalid_hrzjGDDw8z # Replace with your actual key
cert_path: "/path/to/test-certificate.example.com-cert.pem"
key_secret: examplekey_notvalid_hrzbbDDw8z # Replace with your actual key
key_path: "/path/to/test-certificate.example.com-key.pem"
action: "/usr/bin/systemctl reload caddy"
```
Use code with caution.
## Notes
- This documentation assumes you have a basic understanding of YAML syntax. Resources for learning YAML are readily available online.
- Replace placeholder values like `examplekey_notvalid_hrzjGDDw8z` with your actual API keys.

View file

@ -0,0 +1,30 @@
---
title: Installation
weight: 10
---
## Prerequisites
Before building the project, ensure you have the following installed:
- make: A build automation tool
- Go: Version 1.22 or later
## Building the Project from Source
To build the project, first clone the projects git repository, then navigate to the project's root directory and run the following command:
```shell
make build
```
This command will generate the `certwarden-deploy` binary in the `bin/` folder.
## Getting pre-built Binaries
You can also get pre-built binaries from the [releases page](https://code.lila.network/adoralaura/certwarden-deploy/releases). Make sure you get the binaries fitting your architecture!
## Setting up automatic Certificate Renewals
Although not required for `certwarden-deploy` to work, it's highly rrecommended to set up automatic renewals for `certwarden-deploy`, so that you don't need to worry about rolling out your certificates every time they get renewed by CertWarden.
To do that, there are example `systemd` Service and Timer files included in the `examples/` directory of the `certwarden-deploy` repository.
Please make sure to customize them to your requirements (path to `certwarden-deploy` binary, user and group, execution interval...) and then drop them into the `/etc/systemd/system/` directory, then enable the timer with `systemctl enable --now certwarden-deploy.timer`
If you kept the example schedule, `certwarden-deploy` will run every saturday at ~4am.

33
docs/content/license.md Normal file
View file

@ -0,0 +1,33 @@
---
title: License
weight: 99
---
## Documentation
This documentation is available under the [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
## Source Code
The source code of `certwarden-deploy` is available under the MIT license:
```plaintext
MIT License
Copyright © 2024 Adora Laura Kalb <dev@lauka.net>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
```

5
docs/go.mod Normal file
View file

@ -0,0 +1,5 @@
module code.lila.network/adoralaura/certwarden-deploy-docs
go 1.22.2
require github.com/McShelby/hugo-theme-relearn v0.0.0-20240721222908-7aec99b38dc2 // indirect

2
docs/go.sum Normal file
View file

@ -0,0 +1,2 @@
github.com/McShelby/hugo-theme-relearn v0.0.0-20240721222908-7aec99b38dc2 h1:022HGVq2CBuTftLgNRiU3rxqh+w3M3ZcschnXbjgomc=
github.com/McShelby/hugo-theme-relearn v0.0.0-20240721222908-7aec99b38dc2/go.mod h1:mKQQdxZNIlLvAj8X3tMq+RzntIJSr9z7XdzuMomt0IM=

View file

@ -0,0 +1,2 @@
{{ .Params.headingPost | safeHTML }}
<script defer src="https://esseles.adora.codes/script.js" data-website-id="fe4ec517-25b2-4e0d-b502-6bd3a7420849"></script>

View file

@ -0,0 +1 @@
<img src="/images/logo.svg"/>

BIN
docs/static/images/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

1
docs/static/images/logo.svg vendored Normal file
View file

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 3246 924" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><g id="BG"></g><rect id="Artboard1" x="0" y="0" width="3245.03" height="923.786" style="fill:none;"/><rect x="142.173" y="142.589" width="513.711" height="659.756" style="fill:#96c8d1;fill-rule:nonzero;"/><rect x="207.956" y="204.786" width="380.629" height="533.018" style="fill:#cde9e3;fill-rule:nonzero;"/><path d="M518.389,552.593l-55.026,-0l0,109.913l27.444,-24.548l27.582,24.548l-0,-109.913Z" style="fill:#96c96c;fill-rule:nonzero;"/><path d="M536.731,543.491c-0,25.237 -20.549,45.785 -45.924,45.785c-25.375,0 -45.924,-20.548 -45.924,-45.785c0,-25.376 20.549,-45.786 45.924,-45.786c25.375,-0 45.924,20.548 45.924,45.786Z" style="fill:#fbba22;fill-rule:nonzero;"/><path d="M655.884,124.385l-513.711,0c-10.067,0 -18.342,8.275 -18.342,18.342l0,659.756c0,10.068 8.275,18.342 18.342,18.342l513.711,0c10.067,0 18.342,-8.274 18.342,-18.342l-0,-659.894c-0,-10.067 -8.275,-18.204 -18.342,-18.204Zm-18.342,659.757l-477.027,-0l0,-623.211l477.027,0l0,623.211Z" style="fill:#211f1e;fill-rule:nonzero;"/><path d="M206.439,747.458l385.179,-0c5.103,-0 9.24,-4.137 9.24,-9.102l0,-531.501c0,-5.103 -4.137,-9.102 -9.24,-9.102l-385.179,-0c-5.103,-0 -9.24,4.137 -9.24,9.102l-0,531.501c-0,4.965 4.137,9.102 9.24,9.102Zm9.102,-531.501l366.838,-0l-0,513.159l-366.838,-0l-0,-513.159Z" style="fill:#211f1e;fill-rule:nonzero;"/><path d="M341.728,600.723l-55.026,-0c-5.103,-0 -9.24,4.137 -9.24,9.102c-0,5.102 4.137,9.102 9.24,9.102l55.026,-0c5.102,-0 9.239,-4.138 9.239,-9.102c-0.138,-4.965 -4.275,-9.102 -9.239,-9.102Zm-61.922,-201.899l238.445,0c5.103,0 9.24,-4.137 9.24,-9.102c-0,-5.102 -4.137,-9.102 -9.24,-9.102l-238.445,0c-5.102,0 -9.239,4.137 -9.239,9.102c-0,4.965 4.137,9.102 9.239,9.102Zm119.154,36.684l-119.292,-0c-5.102,-0 -9.239,4.137 -9.239,9.102c-0,5.103 4.137,9.102 9.239,9.102l119.292,-0c5.102,-0 9.24,-4.137 9.24,-9.102c-0,-5.103 -4.138,-9.102 -9.24,-9.102Zm-119.154,-91.71l238.445,0c5.103,0 9.24,-4.137 9.24,-9.102c-0,-5.102 -4.137,-9.102 -9.24,-9.102l-238.445,0c-5.102,0 -9.239,4.138 -9.239,9.102c-0,4.965 4.137,9.102 9.239,9.102Zm0,-54.887l238.445,-0c5.103,-0 9.24,-4.138 9.24,-9.102c-0,-5.103 -4.137,-9.102 -9.24,-9.102l-238.445,-0c-5.102,-0 -9.239,4.137 -9.239,9.102c-0,4.964 4.137,9.102 9.239,9.102Zm201.899,201.485c-30.34,-0 -55.026,24.685 -55.026,55.025c0,16.274 7.172,30.754 18.342,40.821l0,78.195c0,3.585 2.069,6.895 5.379,8.412c3.31,1.517 7.171,0.828 9.929,-1.517l21.376,-19.169l21.376,19.169c1.655,1.517 3.861,2.345 6.068,2.345c1.241,-0 2.482,-0.276 3.723,-0.828c3.31,-1.517 5.379,-4.689 5.379,-8.412l-0,-78.195c11.171,-10.067 18.342,-24.685 18.342,-40.821c0.138,-30.34 -24.548,-55.025 -54.888,-55.025Zm18.342,153.492l-12.274,-10.895c-3.448,-3.171 -8.826,-3.171 -12.274,0l-12.274,10.895l0,-46.751c5.792,2.069 11.86,3.172 18.342,3.172c6.482,0 12.55,-1.103 18.342,-3.172l0,46.751l0.138,0Zm-18.342,-61.783c-20.273,0 -36.684,-16.411 -36.684,-36.684c0,-20.272 16.411,-36.683 36.684,-36.683c20.273,-0 36.684,16.411 36.684,36.683c-0,20.273 -16.411,36.684 -36.684,36.684Z" style="fill:#211f1e;fill-rule:nonzero;"/><g transform="matrix(283.53,0,0,283.53,3117.47,579.164)"></g><text x="784.992px" y="579.164px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:283.53px;fill:#fff;">certwarden-deploy</text></svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -17,12 +17,20 @@ certificates:
# Contains the API-Key to fetch the certificate from the server
# required
cert_secret: examplekey_notvalid_hrzjGDDw8z
api_key: examplekey_notvalid_hrzjGDDw8z
# path where to save the certificate
# required
cert_path: "/path/to/test-certificate.example.com-cert.pem"
# Contains the API-Key to fetch the private key from the server
# required
key_secret: examplekey_notvalid_hrzbbDDw8z
# path where to save the private key
# required
key_path: "/path/to/test-certificate.example.com-key.pem"
# action to run when certificate was updated or --force is on
action: "/usr/bin/systemd reload caddy"
# path where to save the certificate
# required
file_path: "/path/to/test-certificate.example.com-cert.pem"

3
go.mod
View file

@ -8,11 +8,8 @@ require (
)
require (
github.com/getsentry/sentry-go v0.28.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
)

6
go.sum
View file

@ -1,7 +1,5 @@
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k=
github.com/getsentry/sentry-go v0.28.1/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -16,10 +14,6 @@ github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View file

@ -102,6 +102,9 @@ func (c *GenericCertificate) Rollout(logger *slog.Logger, baseUrl string, skipIn
if fileNeedsRollout {
logger.Info("New file deployed", "path", c.FilePath)
return true, nil
} else if configuration.Force {
logger.Info("File deployed", "path", c.FilePath)
return true, nil
} else {
logger.Info("File not changed, skipping...", "path", c.FilePath)
return false, nil
@ -192,22 +195,25 @@ func (c *GenericCertificate) writeToDisk(logger *slog.Logger) error {
// Returns error or nil on success.
func (c *GenericCertificate) fetchFromServer(logger *slog.Logger, baseUrl string, skipInsecure bool) error {
var url string
var fileType string
if c.IsKey {
url = baseUrl + constants.CertificateApiPath + c.Name
url = baseUrl + constants.KeyApiPath + c.Name
fileType = "privatekey"
} else {
url = baseUrl + constants.CertificateApiPath + c.Name
fileType = "certificate"
}
logger.Debug("Certificate request URL: " + url)
logger.Debug("Data request URL: "+url, "file-type", fileType)
var transport http.RoundTripper
if skipInsecure {
logger.Debug("TLS Certificate Validation is disabled")
logger.Debug("Upstream Server TLS Certificate Validation is disabled")
transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
} else {
logger.Debug("TLS Certificate Validation is enabled")
logger.Debug("Upstream Server HTTP TLS Certificate Validation is enabled")
}
client := &http.Client{
@ -216,7 +222,7 @@ func (c *GenericCertificate) fetchFromServer(logger *slog.Logger, baseUrl string
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return fmt.Errorf("failed to prepare to request certificate from server: %w", err)
return fmt.Errorf("failed to prepare to request data from server: %w", err)
}
req.Header.Set("User-Agent", constants.UserAgent)
@ -224,7 +230,7 @@ func (c *GenericCertificate) fetchFromServer(logger *slog.Logger, baseUrl string
res, err := client.Do(req)
if err != nil {
return fmt.Errorf("failed to request certificate from server: %w", err)
return fmt.Errorf("failed to request data from server: %w", err)
}
defer func(l *slog.Logger) {
@ -234,15 +240,15 @@ func (c *GenericCertificate) fetchFromServer(logger *slog.Logger, baseUrl string
}(logger)
if res.StatusCode == http.StatusUnauthorized {
logger.Error("API-Key for Certificate is invalid, skipping certificate!", "name", c.Name)
logger.Error("API-Key for request is invalid, skipping certificate!", "name", c.Name, "file-type", fileType)
return errors.New("API-Key invalid")
} else if res.StatusCode != http.StatusOK {
logger.Error("failed to get certificate from server", "name", c.Name, "http-response", res.Status)
logger.Error("failed to get data from server", "name", c.Name, "http-response", res.Status, "file-type", fileType)
}
bodyBytes, err := io.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("failed to read certificate response from server: %w", err)
return fmt.Errorf("failed to read response from server: %w", err)
}
c.serverBytes = bodyBytes

View file

@ -30,14 +30,14 @@ func handleRootCmd(cmd *cobra.Command, args []string) {
slog.Error("failed to initialize config", "error", err)
os.Exit(1)
}
log := logger.InitializeLogger()
log := logger.Initialize()
config.SubstituteKeys(log)
validation := config.IsValid()
if validation.HasMessages() {
validation.Print(log)
slog.Error("The configuration file has errors! Application cannot start unless all errors are corrected!")
panic(1)
os.Exit(1)
}
certificates.HandleCertificates(log, config)

View file

@ -24,7 +24,6 @@ var Force bool
type ConfigFileData struct {
BaseURL string `yaml:"base_url"`
DisableCertificateValidation bool `yaml:"disable_certificate_validation"`
Sentry SentryData `yaml:"sentry,omitempty"`
Certificates []CertificateData `yaml:"certificates"`
}
@ -38,10 +37,6 @@ type CertificateData struct {
Action string `yaml:"action"`
}
type SentryData struct {
DSN string `yaml:"dsn"`
}
type ConfigValidationError struct {
ErrorMessages []string
}
@ -55,7 +50,7 @@ func (e *ConfigValidationError) Add(msg string) {
}
func (e *ConfigValidationError) HasMessages() bool {
return len(e.ErrorMessages) == 0
return len(e.ErrorMessages) != 0
}
func (e *ConfigValidationError) Print(logger *slog.Logger) {

View file

@ -1,7 +1,9 @@
package constants
const Version = "0.2.0"
var Version string
var UserAgent = "certwarden-deploy/" + Version + " +https://code.lila.network/adoralaura/certwarden-deploy"
const CertificateApiPath = "/certwarden/api/v1/download/certificates/"
const KeyApiPath = "/certwarden/api/v1/download/privatekeys/"
const ApiKeyHeaderName = "X-API-Key"
const UserAgent = "certwarden-deploy/" + Version + " +https://code.lila.network/adoralaura/certwarden-deploy"

View file

@ -8,7 +8,8 @@ import (
"code.lila.network/adoralaura/certwarden-deploy/internal/configuration"
)
func InitializeLogger() *slog.Logger {
// Initialize initializes a *slog.Logger with the right log level and options.
func Initialize() *slog.Logger {
logLevel := slog.LevelInfo
if configuration.VerboseLogging {

11
main.go
View file

@ -1,11 +0,0 @@
/*
Copyright © 2024 Laura Kalb <dev@lauka.net>
The code of this project is available under the MIT license. See the LICENSE file for more info.
*/
package main
import cmd "code.lila.network/adoralaura/certwarden-deploy/cmd/certwarden-deploy"
func main() {
cmd.Execute()
}