Lets see if this works
All checks were successful
Build (artifact) / build (push) Successful in 1m13s
All checks were successful
Build (artifact) / build (push) Successful in 1m13s
This commit is contained in:
@@ -44,7 +44,7 @@ jobs:
|
|||||||
run: echo "COMMIT_MSG=$(git log -1 --pretty=%s)" >> $GITHUB_ENV
|
run: echo "COMMIT_MSG=$(git log -1 --pretty=%s)" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: make build
|
run: make client server
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: https://github.com/actions/upload-artifact@v3
|
uses: https://github.com/actions/upload-artifact@v3
|
||||||
|
|||||||
16
Makefile
16
Makefile
@@ -1,4 +1,4 @@
|
|||||||
VERSION := 1.1.5-beta
|
VERSION := 1.1.6-beta
|
||||||
BUILD := $(shell git rev-parse --short HEAD)
|
BUILD := $(shell git rev-parse --short HEAD)
|
||||||
|
|
||||||
GO := go
|
GO := go
|
||||||
@@ -6,7 +6,7 @@ GO := go
|
|||||||
BUILD_FLAGS := -buildmode=pie -trimpath
|
BUILD_FLAGS := -buildmode=pie -trimpath
|
||||||
LDFLAGS := -linkmode=external -extldflags="-Wl,-z,relro,-z,now" -X git.nevets.tech/Keys/certman/common.Version=$(VERSION) -X git.nevets.tech/Keys/certman/common.Build=$(BUILD)
|
LDFLAGS := -linkmode=external -extldflags="-Wl,-z,relro,-z,now" -X git.nevets.tech/Keys/certman/common.Version=$(VERSION) -X git.nevets.tech/Keys/certman/common.Build=$(BUILD)
|
||||||
|
|
||||||
.PHONY: proto bundle client server executor build debug stage
|
.PHONY: proto bundle client server executor build debug stage help
|
||||||
|
|
||||||
proto:
|
proto:
|
||||||
@protoc --go_out=./proto --go-grpc_out=./proto proto/hook.proto
|
@protoc --go_out=./proto --go-grpc_out=./proto proto/hook.proto
|
||||||
@@ -37,4 +37,14 @@ debug: proto
|
|||||||
|
|
||||||
stage: build
|
stage: build
|
||||||
@sudo cp ./certman /srv/vm-passthru/certman
|
@sudo cp ./certman /srv/vm-passthru/certman
|
||||||
@ssh steven@192.168.122.44 updateCertman.sh
|
@ssh steven@192.168.122.44 updateCertman.sh
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "proto - Generate gRPC proto stubs"
|
||||||
|
@echo "bundle - Build bundled binary (client, server, executor)"
|
||||||
|
@echo "client - Build client binary"
|
||||||
|
@echo "server - Build server binary"
|
||||||
|
@echo "executor - Build executor binary"
|
||||||
|
@echo "build - Build all binaries"
|
||||||
|
@echo "debug - Build bundled binary without stripping and hardening"
|
||||||
|
@echo "stage - Build all binaries and upload to dev environment (vm)"
|
||||||
@@ -29,4 +29,7 @@ sudo certman new-domain example.com
|
|||||||
|
|
||||||
## Scratch Board
|
## Scratch Board
|
||||||
- Server Flow
|
- Server Flow
|
||||||
- Read from
|
- Read from
|
||||||
|
|
||||||
|
# Coding Conventions
|
||||||
|
- Keep Config() calls in app space
|
||||||
@@ -47,17 +47,19 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func renewCert(domain string) error {
|
func renewCert(domain string) error {
|
||||||
gitWorkspace := &common.GitWorkspace{
|
|
||||||
Domain: domain,
|
|
||||||
Storage: memory.NewStorage(),
|
|
||||||
FS: memfs.New(),
|
|
||||||
}
|
|
||||||
config := app.Config()
|
config := app.Config()
|
||||||
domainConfig, exists := app.DomainStore().Get(domain)
|
domainConfig, exists := app.DomainStore().Get(domain)
|
||||||
if !exists {
|
if !exists {
|
||||||
return app.ErrConfigNotFound
|
return app.ErrConfigNotFound
|
||||||
}
|
}
|
||||||
if err := client.PullCerts(config, domainConfig, gitWorkspace); err != nil {
|
|
||||||
|
gitWorkspace := &common.GitWorkspace{
|
||||||
|
Domain: domain,
|
||||||
|
URL: config.Git.Server + "/" + config.Git.OrgName + "/" + domain + domainConfig.Repo.RepoSuffix + ".git",
|
||||||
|
Storage: memory.NewStorage(),
|
||||||
|
FS: memfs.New(),
|
||||||
|
}
|
||||||
|
if err := client.PullCerts(config, gitWorkspace); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
certsDir := common.EffectiveDataRoot(config, domainConfig)
|
certsDir := common.EffectiveDataRoot(config, domainConfig)
|
||||||
|
|||||||
@@ -67,13 +67,14 @@ func (d *Daemon) Tick() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gitWorkspace := &common.GitWorkspace{
|
gitWorkspace := &common.GitWorkspace{
|
||||||
|
Domain: domainStr,
|
||||||
|
URL: app.Config().Git.Server + "/" + config.Git.OrgName + "/" + domainStr + domainConfig.Repo.RepoSuffix + ".git",
|
||||||
Storage: memory.NewStorage(),
|
Storage: memory.NewStorage(),
|
||||||
FS: memfs.New(),
|
FS: memfs.New(),
|
||||||
}
|
}
|
||||||
// Ex: https://git.example.com/Org/Repo-suffix.git
|
// Ex: https://git.example.com/Org/Repo-suffix.git
|
||||||
// Clones repo and stores in gitWorkspace, skip if clone fails (doesn't exist?)
|
// Clones repo and stores in gitWorkspace, skip if clone fails (doesn't exist?)
|
||||||
repoUrl := app.Config().Git.Server + "/" + config.Git.OrgName + "/" + domainStr + domainConfig.Repo.RepoSuffix + ".git"
|
err := gitWorkspace.CloneRepo(common.Client, config)
|
||||||
err := common.CloneRepo(repoUrl, gitWorkspace, common.Client, config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error cloning domain repo %s: %v\n", domainStr, err)
|
fmt.Printf("Error cloning domain repo %s: %v\n", domainStr, err)
|
||||||
continue
|
continue
|
||||||
@@ -121,7 +122,8 @@ func (d *Daemon) Tick() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = common.WriteCommitHash(headRef.Hash().String(), config, domainConfig)
|
dataRoot := common.EffectiveDataRoot(config, domainConfig)
|
||||||
|
err = client.WriteCommitHash(headRef.Hash().String(), dataRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error writing commit hash: %v\n", err)
|
fmt.Printf("Error writing commit hash: %v\n", err)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -55,17 +55,17 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func devCmd(cmd *cobra.Command, args []string) {
|
func devCmd(cmd *cobra.Command, args []string) {
|
||||||
testDomain := "lunamc.org"
|
//testDomain := "lunamc.org"
|
||||||
err := LoadConfig()
|
//err := LoadConfig()
|
||||||
if err != nil {
|
//if err != nil {
|
||||||
log.Fatalf("Error loading configuration: %v\n", err)
|
// log.Fatalf("Error loading configuration: %v\n", err)
|
||||||
}
|
//}
|
||||||
err = LoadDomainConfigs()
|
//err = LoadDomainConfigs()
|
||||||
if err != nil {
|
//if err != nil {
|
||||||
log.Fatalf("Error loading configs: %v\n", err)
|
// log.Fatalf("Error loading configs: %v\n", err)
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
fmt.Println(testDomain)
|
//fmt.Println(testDomain)
|
||||||
}
|
}
|
||||||
|
|
||||||
func versionCmd(cmd *cobra.Command, args []string) {
|
func versionCmd(cmd *cobra.Command, args []string) {
|
||||||
|
|||||||
@@ -90,10 +90,9 @@ func renewCerts(domain string, noPush bool, mgr *server.ACMEManager) error {
|
|||||||
FS: memfs.New(),
|
FS: memfs.New(),
|
||||||
}
|
}
|
||||||
|
|
||||||
var repoUrl string
|
|
||||||
if !domainConfig.Internal.RepoExists {
|
if !domainConfig.Internal.RepoExists {
|
||||||
repoUrl = common.CreateGiteaRepo(domain, giteaClient, config, domainConfig)
|
gitWorkspace.URL = common.CreateGiteaRepo(domain, giteaClient, config, domainConfig)
|
||||||
if repoUrl == "" {
|
if gitWorkspace.URL == "" {
|
||||||
return fmt.Errorf("error creating Gitea repo for domain %s", domain)
|
return fmt.Errorf("error creating Gitea repo for domain %s", domain)
|
||||||
}
|
}
|
||||||
domainConfig.Internal.RepoExists = true
|
domainConfig.Internal.RepoExists = true
|
||||||
@@ -102,19 +101,20 @@ func renewCerts(domain string, noPush bool, mgr *server.ACMEManager) error {
|
|||||||
return fmt.Errorf("error saving domain config %s: %v", domain, err)
|
return fmt.Errorf("error saving domain config %s: %v", domain, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = common.InitRepo(repoUrl, gitWorkspace)
|
err = gitWorkspace.InitRepo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error initializing repo for domain %s: %v", domain, err)
|
return fmt.Errorf("error initializing repo for domain %s: %v", domain, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
repoUrl = config.Git.Server + "/" + config.Git.OrgName + "/" + domain + domainConfig.Repo.RepoSuffix + ".git"
|
gitWorkspace.URL = config.Git.Server + "/" + config.Git.OrgName + "/" + domain + domainConfig.Repo.RepoSuffix + ".git"
|
||||||
err = common.CloneRepo(repoUrl, gitWorkspace, common.Server, config)
|
err = gitWorkspace.CloneRepo(common.Server, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error cloning repo for domain %s: %v", domain, err)
|
return fmt.Errorf("error cloning repo for domain %s: %v", domain, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = common.AddAndPushCerts(domain, gitWorkspace, config, domainConfig)
|
dataRoot := common.EffectiveDataRoot(config, domainConfig)
|
||||||
|
err = server.AddAndPushCerts(gitWorkspace, dataRoot, domainConfig.Repo.RepoSuffix, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error pushing certificates for domain %s: %v", domain, err)
|
return fmt.Errorf("error pushing certificates for domain %s: %v", domain, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,10 +113,9 @@ func (d *Daemon) Tick() {
|
|||||||
FS: memfs.New(),
|
FS: memfs.New(),
|
||||||
}
|
}
|
||||||
|
|
||||||
var repoUrl string
|
|
||||||
if !domainConfig.Internal.RepoExists {
|
if !domainConfig.Internal.RepoExists {
|
||||||
repoUrl = common.CreateGiteaRepo(domainStr, giteaClient, config, domainConfig)
|
gitWorkspace.URL = common.CreateGiteaRepo(domainStr, giteaClient, config, domainConfig)
|
||||||
if repoUrl == "" {
|
if gitWorkspace.URL == "" {
|
||||||
fmt.Printf("Error creating Gitea repo for domain %s\n", domainStr)
|
fmt.Printf("Error creating Gitea repo for domain %s\n", domainStr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -127,21 +126,22 @@ func (d *Daemon) Tick() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = common.InitRepo(repoUrl, gitWorkspace)
|
err = gitWorkspace.InitRepo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error initializing repo for domain %s: %v\n", domainStr, err)
|
fmt.Printf("Error initializing repo for domain %s: %v\n", domainStr, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
repoUrl = appShared.Config().Git.Server + "/" + appShared.Config().Git.OrgName + "/" + domainStr + domainConfig.Repo.RepoSuffix + ".git"
|
gitWorkspace.URL = appShared.Config().Git.Server + "/" + appShared.Config().Git.OrgName + "/" + domainStr + domainConfig.Repo.RepoSuffix + ".git"
|
||||||
err = common.CloneRepo(repoUrl, gitWorkspace, common.Server, config)
|
err = gitWorkspace.CloneRepo(common.Server, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error cloning repo for domain %s: %v\n", domainStr, err)
|
fmt.Printf("Error cloning repo for domain %s: %v\n", domainStr, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = common.AddAndPushCerts(domainStr, gitWorkspace, config, domainConfig)
|
dataRoot := common.EffectiveDataRoot(config, domainConfig)
|
||||||
|
err = server.AddAndPushCerts(gitWorkspace, dataRoot, domainConfig.Repo.RepoSuffix, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error pushing certificates for domain %s: %v\n", domainStr, err)
|
fmt.Printf("Error pushing certificates for domain %s: %v\n", domainStr, err)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -1,7 +1,37 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"git.nevets.tech/Steven/certman/app"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("Hello server")
|
rootCmd := &cobra.Command{
|
||||||
|
Use: "certman",
|
||||||
|
Short: "CertMan",
|
||||||
|
Long: "Certificate Manager",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
return cmd.Help()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rootCmd.AddCommand(app.VersionCmd)
|
||||||
|
rootCmd.AddCommand(app.NewKeyCmd)
|
||||||
|
rootCmd.AddCommand(app.DevCmd)
|
||||||
|
|
||||||
|
rootCmd.AddCommand(app.NewDomainCmd)
|
||||||
|
//-----------------------------------
|
||||||
|
rootCmd.AddCommand(app.InstallCmd)
|
||||||
|
|
||||||
|
rootCmd.AddCommand(app.CertCmd)
|
||||||
|
|
||||||
|
rootCmd.AddCommand(app.DaemonCmd)
|
||||||
|
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,10 @@ import (
|
|||||||
"git.nevets.tech/Steven/certman/common"
|
"git.nevets.tech/Steven/certman/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PullCerts(config *common.AppConfig, domainConfig *common.DomainConfig, gitWorkspace *common.GitWorkspace) error {
|
func PullCerts(config *common.AppConfig, gitWorkspace *common.GitWorkspace) error {
|
||||||
// Ex: https://git.example.com/Org/Repo-suffix.git
|
// Ex: https://git.example.com/Org/Repo-suffix.git
|
||||||
// Clones repo and stores in gitWorkspace, skip if clone fails (doesn't exist?)
|
// Clones repo and stores in gitWorkspace, skip if clone fails (doesn't exist?)
|
||||||
repoUrl := config.Git.Server + "/" + config.Git.OrgName + "/" + gitWorkspace.Domain + domainConfig.Repo.RepoSuffix + ".git"
|
err := gitWorkspace.CloneRepo(common.Client, config)
|
||||||
err := common.CloneRepo(repoUrl, gitWorkspace, common.Client, config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error cloning domain repo %s: %v\n", gitWorkspace.Domain, err)
|
return fmt.Errorf("Error cloning domain repo %s: %v\n", gitWorkspace.Domain, err)
|
||||||
}
|
}
|
||||||
@@ -60,7 +59,8 @@ func DecryptAndWriteCertificates(certsDir string, config *common.AppConfig, doma
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = common.WriteCommitHash(headRef.Hash().String(), config, domainConfig)
|
dataRoot := common.EffectiveDataRoot(config, domainConfig)
|
||||||
|
err = WriteCommitHash(headRef.Hash().String(), dataRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error writing commit hash: %v\n", err)
|
fmt.Printf("Error writing commit hash: %v\n", err)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ func NewACMEManager(config *common.AppConfig) (*ACMEManager, error) {
|
|||||||
return nil, fmt.Errorf("cloudflare dns provider: %w", err)
|
return nil, fmt.Errorf("cloudflare dns provider: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := client.Challenge.SetDNS01Provider(cfProvider); err != nil {
|
if err = client.Challenge.SetDNS01Provider(cfProvider); err != nil {
|
||||||
return nil, fmt.Errorf("set dns-01 provider: %w", err)
|
return nil, fmt.Errorf("set dns-01 provider: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ func NewACMEManager(config *common.AppConfig) (*ACMEManager, error) {
|
|||||||
return nil, fmt.Errorf("acme registration: %w", err)
|
return nil, fmt.Errorf("acme registration: %w", err)
|
||||||
}
|
}
|
||||||
mgr.User.Registration = reg
|
mgr.User.Registration = reg
|
||||||
if err := saveACMEUser(mgr.accountRoot, mgr.User); err != nil {
|
if err = saveACMEUser(mgr.accountRoot, mgr.User); err != nil {
|
||||||
return nil, fmt.Errorf("save acme User registration: %w", err)
|
return nil, fmt.Errorf("save acme User registration: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,6 +270,7 @@ func buildDomainRuntimeConfig(config *common.AppConfig, domainConfig *common.Dom
|
|||||||
// If a subdomain entry looks like a full FQDN already, it is used as-is.
|
// If a subdomain entry looks like a full FQDN already, it is used as-is.
|
||||||
func buildDomainList(baseDomain string, subs []string) []string {
|
func buildDomainList(baseDomain string, subs []string) []string {
|
||||||
seen := map[string]struct{}{}
|
seen := map[string]struct{}{}
|
||||||
|
out := make([]string, 0, len(subs)+1)
|
||||||
add := func(d string) {
|
add := func(d string) {
|
||||||
d = strings.TrimSpace(strings.ToLower(d))
|
d = strings.TrimSpace(strings.ToLower(d))
|
||||||
if d == "" {
|
if d == "" {
|
||||||
@@ -279,6 +280,7 @@ func buildDomainList(baseDomain string, subs []string) []string {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
seen[d] = struct{}{}
|
seen[d] = struct{}{}
|
||||||
|
out = append(out, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
add(baseDomain)
|
add(baseDomain)
|
||||||
@@ -310,10 +312,6 @@ func buildDomainList(baseDomain string, subs []string) []string {
|
|||||||
add(s + "." + baseDomain)
|
add(s + "." + baseDomain)
|
||||||
}
|
}
|
||||||
|
|
||||||
out := make([]string, 0, len(seen))
|
|
||||||
for d := range seen {
|
|
||||||
out = append(out, d)
|
|
||||||
}
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
15
server/acme_manager_test.go
Normal file
15
server/acme_manager_test.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuildDomainList(t *testing.T) {
|
||||||
|
domains := buildDomainList("example.com", []string{"*", "dev"})
|
||||||
|
fmt.Printf("domains: %v\n", domains)
|
||||||
|
if slices.Compare(domains, []string{"example.com", "*.example.com", "dev.example.com"}) != 0 {
|
||||||
|
t.Errorf("domains not equal")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,9 +14,7 @@ import (
|
|||||||
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GitWorkspace common.GitWorkspace
|
func AddAndPushCerts(ws *common.GitWorkspace, dataRoot, repoSuffix string, config *common.AppConfig) error {
|
||||||
|
|
||||||
func (ws *GitWorkspace) AddAndPushCerts(dataRoot, repoSuffix string, config *common.AppConfig) error {
|
|
||||||
certFiles, err := os.ReadDir(dataRoot)
|
certFiles, err := os.ReadDir(dataRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error reading from directory: %v\n", err)
|
fmt.Printf("Error reading from directory: %v\n", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user