Add Vault certificate rotation operator
This commit is contained in:
parent
c685229437
commit
8009b5fd9c
1 changed files with 1013 additions and 0 deletions
96
internal/rotator/http.go
Normal file
96
internal/rotator/http.go
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
package rotator
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func tlsClient(certificatePaths []string, serverName string) (*http.Client, error) {
|
||||
pool, err := certificatePool(certificatePaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
transport.TLSClientConfig = &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
RootCAs: pool,
|
||||
ServerName: serverName,
|
||||
}
|
||||
return &http.Client{Transport: transport, Timeout: 20 * time.Second}, nil
|
||||
}
|
||||
|
||||
func certificatePool(certificatePaths []string) (*x509.CertPool, error) {
|
||||
pool := x509.NewCertPool()
|
||||
for _, path := range certificatePaths {
|
||||
certificate, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read CA certificate %s: %w", path, err)
|
||||
}
|
||||
if !pool.AppendCertsFromPEM(certificate) {
|
||||
return nil, fmt.Errorf("parse CA certificate %s", path)
|
||||
}
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func jsonRequest(ctx context.Context, client *http.Client, method, endpoint string, body any, headers map[string]string, output any) (*http.Response, error) {
|
||||
var payload io.Reader
|
||||
if body != nil {
|
||||
encoded, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("encode request: %w", err)
|
||||
}
|
||||
payload = bytes.NewReader(encoded)
|
||||
}
|
||||
request, err := http.NewRequestWithContext(ctx, method, endpoint, payload)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create request: %w", err)
|
||||
}
|
||||
if body != nil {
|
||||
request.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
for name, value := range headers {
|
||||
request.Header.Set(name, value)
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = response.Body.Close() }()
|
||||
limited := io.LimitReader(response.Body, 1<<20)
|
||||
if response.StatusCode < 200 || response.StatusCode >= 300 {
|
||||
_, _ = io.Copy(io.Discard, limited)
|
||||
return response, fmt.Errorf("%s returned HTTP %d", request.URL.Path, response.StatusCode)
|
||||
}
|
||||
if output == nil {
|
||||
_, err = io.Copy(io.Discard, limited)
|
||||
return response, err
|
||||
}
|
||||
decoder := json.NewDecoder(limited)
|
||||
if err := decoder.Decode(output); err != nil {
|
||||
return response, fmt.Errorf("decode %s response: %w", request.URL.Path, err)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func readTrimmed(path string) (string, error) {
|
||||
value, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
trimmed := strings.TrimSpace(string(value))
|
||||
if trimmed == "" {
|
||||
return "", errors.New("file is empty")
|
||||
}
|
||||
return trimmed, nil
|
||||
}
|
||||
Loading…
Reference in a new issue