Lets Encrypt certificate renewal API for server cluster and getssl.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
5.8 KiB

//LEAPI - ACME Certificate Renewal Control API - Copyright 2022-2024 Ruel Tmeizeh All Rights Reserved
package main
import (
"crypto/tls"
"encoding/json"
"errors"
"io/ioutil"
"log"
"net/http"
"strconv"
"sync"
)
func syncAllServers() error {
var theError error
numservers := len(servers)
c := make(chan string)
var wg sync.WaitGroup
wg.Add(numservers)
for n := 0; n < numservers; n++ {
go func(c chan string) {
for {
srv, more := <-c
if more == false {
wg.Done()
return
}
log.Println("Parallel execution sync of server: " + srv + "...")
err := syncOneServer(srv)
if err != nil {
log.Println(err.Error())
theError = err
}
}
}(c)
}
for _, server := range servers { //send each server to the channel
if server == appconf.Hostname { //don't send myself
continue
}
c <- server
}
close(c)
wg.Wait()
log.Println("Finished sending sync requests.")
return theError //if any one or more fail, return an error for it (the last one that fails)
}
func syncOneServer(server string) error {
//Make http requests to each other servers' /sync endpoints
// https://server.tld:port/sync
log.Println("SYNC " + server + " starting...")
req, err := http.NewRequest("POST", syncScheme+server+":"+syncPort+"/api/sync/"+appconf.Hostname, nil)
if err != nil {
log.Println(err.Error())
return errors.New("Couldn't create new HTTP sync request for server: " + server)
}
req.Close = true
req.Header.Set("User-Agent", myUserAgent)
req.Header.Set("Authorization", "Bearer "+appconf.SecretKey)
//skip verification of cert for https syncing, since the cert may not be setup properly at first
customTransport := http.DefaultTransport.(*http.Transport).Clone()
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
client := &http.Client{Transport: customTransport, Timeout: timeout}
//client := &http.Client{Timeout: timeout}
response, err := client.Do(req)
if err != nil {
log.Println(err.Error())
return errors.New("Couldn't perform HTTP sync request to server: " + server)
}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Println(err.Error())
return errors.New("Couldn't parse response body on request to server: " + server)
}
if response.StatusCode != 200 {
errorString := "Problem syncing to server " + server + ". Status code: " + strconv.Itoa(response.StatusCode) + " Body: " + string(body)
log.Println(errorString)
return errors.New(errorString)
}
log.Println("SYNC " + server + " success!")
return nil
}
func syncServersFromHost(host string) error {
var theError error
req, err := http.NewRequest("GET", syncScheme+host+":"+syncPort+"/api/servers", nil)
if err != nil {
log.Println(err.Error())
return errors.New("Couldn't create new HTTP request for syncing servers from host: " + host)
}
req.Close = true
req.Header.Set("User-Agent", myUserAgent)
req.Header.Set("Authorization", "Bearer "+appconf.SecretKey)
//skip verification of cert for https syncing, since the cert may not be setup properly at first
customTransport := http.DefaultTransport.(*http.Transport).Clone()
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
client := &http.Client{Transport: customTransport, Timeout: timeout}
//client := &http.Client{Timeout: timeout}
response, err := client.Do(req)
if err != nil {
log.Println(err.Error())
return errors.New("Couldn't perform HTTP server sync request to host: " + host)
}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Println(err.Error())
return errors.New("Couldn't parse response body from server sync request to server: " + host)
}
if response.StatusCode != 200 {
theError = errors.New("Problem syncing servers from host " + host + ". Status code: " + strconv.Itoa(response.StatusCode) + " Body: " + string(body))
log.Println(theError.Error())
return theError
}
var result APIOutput
err = json.Unmarshal(body, &result)
if err != nil {
log.Println(err.Error())
return errors.New("Couldn't parse response body from host " + host + ": " + err.Error())
}
servers = result.Data
err = writeServers()
if err != nil {
log.Println(err.Error())
return err
}
return nil
}
func syncDomainsFromHost(host string) error {
var theError error
req, err := http.NewRequest("GET", syncScheme+host+":"+syncPort+"/api/domains", nil)
if err != nil {
log.Println(err.Error())
return errors.New("Couldn't create new HTTP request for syncing domains from host: " + host)
}
req.Close = true
req.Header.Set("User-Agent", myUserAgent)
req.Header.Set("Authorization", "Bearer "+appconf.SecretKey)
//skip verification of cert for https syncing, since the cert may not be setup properly at first
customTransport := http.DefaultTransport.(*http.Transport).Clone()
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
client := &http.Client{Transport: customTransport, Timeout: timeout}
//client := &http.Client{Timeout: timeout}
response, err := client.Do(req)
if err != nil {
log.Println(err.Error())
return errors.New("Couldn't perform HTTP domain sync request to host: " + host)
}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Println(err.Error())
return errors.New("Couldn't parse response body from domain sync request to server: " + host)
}
if response.StatusCode != 200 {
theError = errors.New("Problem syncing domains from host " + host + ". Status code: " + strconv.Itoa(response.StatusCode) + " Body: " + string(body))
log.Println(theError.Error())
return theError
}
var result APIOutput
err = json.Unmarshal(body, &result)
if err != nil {
log.Println(err.Error())
return errors.New("Couldn't parse response body from host " + host + ": " + err.Error())
}
domains = result.Data
err = writeDomains()
if err != nil {
log.Println(err.Error())
return err
}
return nil
}