mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
[fixes 31700] Add mTLS support for http backend by way of client cert & key, as well as enterprise cacert. (#31699)
* Add mTLS support for http backend by way of client cert & key, as well as enterprise cacert. * Fix style. * Skip cert validation to be sure error is related to missing client cert; not untrusted server cert. * Remove misplaced err check. * Fix the size of test using http backend. * Just for correctness, include all certs in the pem encoded cert - sometimes certs come with a chain of their signers. * Adjusted names as recommended in PR comments. * Adjusted names to be full-length and more descriptive. * Added full-fledged testing with mTLS http server * Fix goimports. * Fix the names of the backend config. * Exclusive lock for write and delete. * Revert "Fix goimports." This reverts commit 7d40f6099fbbb675fb2e25e35ee40aeafe3d0a22. * goimports just for server test. * Added the go:generation for the mock. * Move the TLS configuration out to make it more readable - don't replace the HTTPClient as the retryablehttp already creates one - just configure its TLS. * Just switch the client/data params - felt more natural this way. * Update internal/backend/remote-state/http/backend.go Co-authored-by: kmoe <5575356+kmoe@users.noreply.github.com> * Update internal/backend/remote-state/http/testdata/gencerts.sh Co-authored-by: kmoe <5575356+kmoe@users.noreply.github.com> * Update internal/backend/remote-state/http/backend.go Co-authored-by: kmoe <5575356+kmoe@users.noreply.github.com> * Update internal/backend/remote-state/http/backend.go Co-authored-by: kmoe <5575356+kmoe@users.noreply.github.com> * Update internal/backend/remote-state/http/backend.go Co-authored-by: kmoe <5575356+kmoe@users.noreply.github.com> * Update internal/backend/remote-state/http/backend.go Co-authored-by: kmoe <5575356+kmoe@users.noreply.github.com> * the location of the file name is not sensitive. * Added error if only one of client_certificate_pem and client_private_key_pem are set. * Remove testify from test cases; use t.Error* for assert and t.Fatal* for require. * Fixed import consistency * Just use default openssl. * Since file(...) is so trivial to use, changed the client cert, key, and ca cert to be the data. See also https://github.com/hashicorp/terraform-provider-http/pull/211 Co-authored-by: Sheridan C Rawlins <scr@ouryahoo.com> Co-authored-by: kmoe <5575356+kmoe@users.noreply.github.com>
This commit is contained in:
parent
7d2afaa2af
commit
75e5ae27a2
2
go.mod
2
go.mod
@ -169,7 +169,7 @@ require (
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/objx v0.1.1 // indirect
|
||||
github.com/stretchr/objx v0.5.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.8 // indirect
|
||||
github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect
|
||||
github.com/vmihailenco/tagparser v0.1.1 // indirect
|
||||
|
7
go.sum
7
go.sum
@ -595,14 +595,17 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.194/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.232 h1:kwsWbh4rEw42ZDe9/812ebhbwNZxlQyZ2sTmxBOKhN4=
|
||||
|
@ -3,14 +3,16 @@ package http
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-cleanhttp"
|
||||
"github.com/hashicorp/go-retryablehttp"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/backend"
|
||||
"github.com/hashicorp/terraform/internal/legacy/helper/schema"
|
||||
"github.com/hashicorp/terraform/internal/logging"
|
||||
@ -93,6 +95,24 @@ func New() backend.Backend {
|
||||
DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_RETRY_WAIT_MAX", 30),
|
||||
Description: "The maximum time in seconds to wait between HTTP request attempts.",
|
||||
},
|
||||
"client_ca_certificate_pem": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_CLIENT_CA_CERTIFICATE_PEM", ""),
|
||||
Description: "A PEM-encoded CA certificate chain used by the client to verify server certificates during TLS authentication.",
|
||||
},
|
||||
"client_certificate_pem": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_CLIENT_CERTIFICATE_PEM", ""),
|
||||
Description: "A PEM-encoded certificate used by the server to verify the client during mutual TLS (mTLS) authentication.",
|
||||
},
|
||||
"client_private_key_pem": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_CLIENT_PRIVATE_KEY_PEM", ""),
|
||||
Description: "A PEM-encoded private key, required if client_certificate_pem is specified.",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -107,6 +127,50 @@ type Backend struct {
|
||||
client *httpClient
|
||||
}
|
||||
|
||||
// configureTLS configures TLS when needed; if there are no conditions requiring TLS, no change is made.
|
||||
func (b *Backend) configureTLS(client *retryablehttp.Client, data *schema.ResourceData) error {
|
||||
// If there are no conditions needing to configure TLS, leave the client untouched
|
||||
skipCertVerification := data.Get("skip_cert_verification").(bool)
|
||||
clientCACertificatePem := data.Get("client_ca_certificate_pem").(string)
|
||||
clientCertificatePem := data.Get("client_certificate_pem").(string)
|
||||
clientPrivateKeyPem := data.Get("client_private_key_pem").(string)
|
||||
if !skipCertVerification && clientCACertificatePem == "" && clientCertificatePem == "" && clientPrivateKeyPem == "" {
|
||||
return nil
|
||||
}
|
||||
if clientCertificatePem != "" && clientPrivateKeyPem == "" {
|
||||
return fmt.Errorf("client_certificate_pem is set but client_private_key_pem is not")
|
||||
}
|
||||
if clientPrivateKeyPem != "" && clientCertificatePem == "" {
|
||||
return fmt.Errorf("client_private_key_pem is set but client_certificate_pem is not")
|
||||
}
|
||||
|
||||
// TLS configuration is needed; create an object and configure it
|
||||
var tlsConfig tls.Config
|
||||
client.HTTPClient.Transport.(*http.Transport).TLSClientConfig = &tlsConfig
|
||||
|
||||
if skipCertVerification {
|
||||
// ignores TLS verification
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
}
|
||||
if clientCACertificatePem != "" {
|
||||
// trust servers based on a CA
|
||||
tlsConfig.RootCAs = x509.NewCertPool()
|
||||
if !tlsConfig.RootCAs.AppendCertsFromPEM([]byte(clientCACertificatePem)) {
|
||||
return errors.New("failed to append certs")
|
||||
}
|
||||
}
|
||||
if clientCertificatePem != "" && clientPrivateKeyPem != "" {
|
||||
// attach a client certificate to the TLS handshake (aka mTLS)
|
||||
certificate, err := tls.X509KeyPair([]byte(clientCertificatePem), []byte(clientPrivateKeyPem))
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load client certificate: %w", err)
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{certificate}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Backend) configure(ctx context.Context) error {
|
||||
data := schema.FromContextBackendConfig(ctx)
|
||||
|
||||
@ -149,21 +213,14 @@ func (b *Backend) configure(ctx context.Context) error {
|
||||
|
||||
unlockMethod := data.Get("unlock_method").(string)
|
||||
|
||||
client := cleanhttp.DefaultPooledClient()
|
||||
|
||||
if data.Get("skip_cert_verification").(bool) {
|
||||
// ignores TLS verification
|
||||
client.Transport.(*http.Transport).TLSClientConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
}
|
||||
|
||||
rClient := retryablehttp.NewClient()
|
||||
rClient.HTTPClient = client
|
||||
rClient.RetryMax = data.Get("retry_max").(int)
|
||||
rClient.RetryWaitMin = time.Duration(data.Get("retry_wait_min").(int)) * time.Second
|
||||
rClient.RetryWaitMax = time.Duration(data.Get("retry_wait_max").(int)) * time.Second
|
||||
rClient.Logger = log.New(logging.LogOutput(), "", log.Flags())
|
||||
if err = b.configureTLS(rClient, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.client = &httpClient{
|
||||
URL: updateURL,
|
||||
|
95
internal/backend/remote-state/http/mock_server_test.go
Normal file
95
internal/backend/remote-state/http/mock_server_test.go
Normal file
@ -0,0 +1,95 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: server_test.go
|
||||
|
||||
// Package http is a generated GoMock package.
|
||||
package http
|
||||
|
||||
import (
|
||||
http "net/http"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockHttpServerCallback is a mock of HttpServerCallback interface.
|
||||
type MockHttpServerCallback struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockHttpServerCallbackMockRecorder
|
||||
}
|
||||
|
||||
// MockHttpServerCallbackMockRecorder is the mock recorder for MockHttpServerCallback.
|
||||
type MockHttpServerCallbackMockRecorder struct {
|
||||
mock *MockHttpServerCallback
|
||||
}
|
||||
|
||||
// NewMockHttpServerCallback creates a new mock instance.
|
||||
func NewMockHttpServerCallback(ctrl *gomock.Controller) *MockHttpServerCallback {
|
||||
mock := &MockHttpServerCallback{ctrl: ctrl}
|
||||
mock.recorder = &MockHttpServerCallbackMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockHttpServerCallback) EXPECT() *MockHttpServerCallbackMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// StateDELETE mocks base method.
|
||||
func (m *MockHttpServerCallback) StateDELETE(req *http.Request) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "StateDELETE", req)
|
||||
}
|
||||
|
||||
// StateDELETE indicates an expected call of StateDELETE.
|
||||
func (mr *MockHttpServerCallbackMockRecorder) StateDELETE(req interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateDELETE", reflect.TypeOf((*MockHttpServerCallback)(nil).StateDELETE), req)
|
||||
}
|
||||
|
||||
// StateGET mocks base method.
|
||||
func (m *MockHttpServerCallback) StateGET(req *http.Request) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "StateGET", req)
|
||||
}
|
||||
|
||||
// StateGET indicates an expected call of StateGET.
|
||||
func (mr *MockHttpServerCallbackMockRecorder) StateGET(req interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateGET", reflect.TypeOf((*MockHttpServerCallback)(nil).StateGET), req)
|
||||
}
|
||||
|
||||
// StateLOCK mocks base method.
|
||||
func (m *MockHttpServerCallback) StateLOCK(req *http.Request) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "StateLOCK", req)
|
||||
}
|
||||
|
||||
// StateLOCK indicates an expected call of StateLOCK.
|
||||
func (mr *MockHttpServerCallbackMockRecorder) StateLOCK(req interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateLOCK", reflect.TypeOf((*MockHttpServerCallback)(nil).StateLOCK), req)
|
||||
}
|
||||
|
||||
// StatePOST mocks base method.
|
||||
func (m *MockHttpServerCallback) StatePOST(req *http.Request) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "StatePOST", req)
|
||||
}
|
||||
|
||||
// StatePOST indicates an expected call of StatePOST.
|
||||
func (mr *MockHttpServerCallbackMockRecorder) StatePOST(req interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StatePOST", reflect.TypeOf((*MockHttpServerCallback)(nil).StatePOST), req)
|
||||
}
|
||||
|
||||
// StateUNLOCK mocks base method.
|
||||
func (m *MockHttpServerCallback) StateUNLOCK(req *http.Request) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "StateUNLOCK", req)
|
||||
}
|
||||
|
||||
// StateUNLOCK indicates an expected call of StateUNLOCK.
|
||||
func (mr *MockHttpServerCallbackMockRecorder) StateUNLOCK(req interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateUNLOCK", reflect.TypeOf((*MockHttpServerCallback)(nil).StateUNLOCK), req)
|
||||
}
|
422
internal/backend/remote-state/http/server_test.go
Normal file
422
internal/backend/remote-state/http/server_test.go
Normal file
@ -0,0 +1,422 @@
|
||||
package http
|
||||
|
||||
//go:generate go run github.com/golang/mock/mockgen -package $GOPACKAGE -source $GOFILE -destination mock_$GOFILE
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
"github.com/hashicorp/terraform/internal/backend"
|
||||
"github.com/hashicorp/terraform/internal/configs"
|
||||
"github.com/hashicorp/terraform/internal/states"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
const sampleState = `
|
||||
{
|
||||
"version": 4,
|
||||
"serial": 0,
|
||||
"lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
|
||||
"remote": {
|
||||
"type": "http",
|
||||
"config": {
|
||||
"path": "local-state.tfstate"
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
type (
|
||||
HttpServerCallback interface {
|
||||
StateGET(req *http.Request)
|
||||
StatePOST(req *http.Request)
|
||||
StateDELETE(req *http.Request)
|
||||
StateLOCK(req *http.Request)
|
||||
StateUNLOCK(req *http.Request)
|
||||
}
|
||||
httpServer struct {
|
||||
r *http.ServeMux
|
||||
data map[string]string
|
||||
locks map[string]string
|
||||
lock sync.RWMutex
|
||||
|
||||
httpServerCallback HttpServerCallback
|
||||
}
|
||||
httpServerOpt func(*httpServer)
|
||||
)
|
||||
|
||||
func withHttpServerCallback(callback HttpServerCallback) httpServerOpt {
|
||||
return func(s *httpServer) {
|
||||
s.httpServerCallback = callback
|
||||
}
|
||||
}
|
||||
|
||||
func newHttpServer(opts ...httpServerOpt) *httpServer {
|
||||
r := http.NewServeMux()
|
||||
s := &httpServer{
|
||||
r: r,
|
||||
data: make(map[string]string),
|
||||
locks: make(map[string]string),
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
s.data["sample"] = sampleState
|
||||
r.HandleFunc("/state/", s.handleState)
|
||||
return s
|
||||
}
|
||||
|
||||
func (h *httpServer) getResource(req *http.Request) string {
|
||||
switch pathParts := strings.SplitN(req.URL.Path, string(filepath.Separator), 3); len(pathParts) {
|
||||
case 3:
|
||||
return pathParts[2]
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (h *httpServer) handleState(writer http.ResponseWriter, req *http.Request) {
|
||||
switch req.Method {
|
||||
case "GET":
|
||||
h.handleStateGET(writer, req)
|
||||
case "POST":
|
||||
h.handleStatePOST(writer, req)
|
||||
case "DELETE":
|
||||
h.handleStateDELETE(writer, req)
|
||||
case "LOCK":
|
||||
h.handleStateLOCK(writer, req)
|
||||
case "UNLOCK":
|
||||
h.handleStateUNLOCK(writer, req)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *httpServer) handleStateGET(writer http.ResponseWriter, req *http.Request) {
|
||||
if h.httpServerCallback != nil {
|
||||
defer h.httpServerCallback.StateGET(req)
|
||||
}
|
||||
resource := h.getResource(req)
|
||||
|
||||
h.lock.RLock()
|
||||
defer h.lock.RUnlock()
|
||||
|
||||
if state, ok := h.data[resource]; ok {
|
||||
_, _ = io.WriteString(writer, state)
|
||||
} else {
|
||||
writer.WriteHeader(http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *httpServer) handleStatePOST(writer http.ResponseWriter, req *http.Request) {
|
||||
if h.httpServerCallback != nil {
|
||||
defer h.httpServerCallback.StatePOST(req)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
resource := h.getResource(req)
|
||||
|
||||
data, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
writer.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
h.lock.Lock()
|
||||
defer h.lock.Unlock()
|
||||
|
||||
h.data[resource] = string(data)
|
||||
writer.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (h *httpServer) handleStateDELETE(writer http.ResponseWriter, req *http.Request) {
|
||||
if h.httpServerCallback != nil {
|
||||
defer h.httpServerCallback.StateDELETE(req)
|
||||
}
|
||||
resource := h.getResource(req)
|
||||
|
||||
h.lock.Lock()
|
||||
defer h.lock.Unlock()
|
||||
|
||||
delete(h.data, resource)
|
||||
writer.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (h *httpServer) handleStateLOCK(writer http.ResponseWriter, req *http.Request) {
|
||||
if h.httpServerCallback != nil {
|
||||
defer h.httpServerCallback.StateLOCK(req)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
resource := h.getResource(req)
|
||||
|
||||
data, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
writer.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
h.lock.Lock()
|
||||
defer h.lock.Unlock()
|
||||
|
||||
if existingLock, ok := h.locks[resource]; ok {
|
||||
writer.WriteHeader(http.StatusLocked)
|
||||
_, _ = io.WriteString(writer, existingLock)
|
||||
} else {
|
||||
h.locks[resource] = string(data)
|
||||
_, _ = io.WriteString(writer, existingLock)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *httpServer) handleStateUNLOCK(writer http.ResponseWriter, req *http.Request) {
|
||||
if h.httpServerCallback != nil {
|
||||
defer h.httpServerCallback.StateUNLOCK(req)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
resource := h.getResource(req)
|
||||
|
||||
data, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
writer.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
var lockInfo map[string]interface{}
|
||||
if err = json.Unmarshal(data, &lockInfo); err != nil {
|
||||
writer.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
h.lock.Lock()
|
||||
defer h.lock.Unlock()
|
||||
|
||||
if existingLock, ok := h.locks[resource]; ok {
|
||||
var existingLockInfo map[string]interface{}
|
||||
if err = json.Unmarshal([]byte(existingLock), &existingLockInfo); err != nil {
|
||||
writer.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
lockID := lockInfo["ID"].(string)
|
||||
existingID := existingLockInfo["ID"].(string)
|
||||
if lockID != existingID {
|
||||
writer.WriteHeader(http.StatusConflict)
|
||||
_, _ = io.WriteString(writer, existingLock)
|
||||
} else {
|
||||
delete(h.locks, resource)
|
||||
_, _ = io.WriteString(writer, existingLock)
|
||||
}
|
||||
} else {
|
||||
writer.WriteHeader(http.StatusConflict)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *httpServer) handler() http.Handler {
|
||||
return h.r
|
||||
}
|
||||
|
||||
func NewHttpTestServer(opts ...httpServerOpt) (*httptest.Server, error) {
|
||||
clientCAData, err := os.ReadFile("testdata/certs/ca.cert.pem")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clientCAs := x509.NewCertPool()
|
||||
clientCAs.AppendCertsFromPEM(clientCAData)
|
||||
|
||||
cert, err := tls.LoadX509KeyPair("testdata/certs/server.crt", "testdata/certs/server.key")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h := newHttpServer(opts...)
|
||||
s := httptest.NewUnstartedServer(h.handler())
|
||||
s.TLS = &tls.Config{
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
ClientCAs: clientCAs,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
|
||||
s.StartTLS()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func TestMTLSServer_NoCertFails(t *testing.T) {
|
||||
// Ensure that no calls are made to the server - everything is blocked by the tls.RequireAndVerifyClientCert
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
mockCallback := NewMockHttpServerCallback(ctrl)
|
||||
|
||||
// Fire up a test server
|
||||
ts, err := NewHttpTestServer(withHttpServerCallback(mockCallback))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error creating test server: %v", err)
|
||||
}
|
||||
defer ts.Close()
|
||||
|
||||
// Configure the backend to the pre-populated sample state
|
||||
url := ts.URL + "/state/sample"
|
||||
conf := map[string]cty.Value{
|
||||
"address": cty.StringVal(url),
|
||||
"skip_cert_verification": cty.BoolVal(true),
|
||||
}
|
||||
b := backend.TestBackendConfig(t, New(), configs.SynthBody("synth", conf)).(*Backend)
|
||||
if nil == b {
|
||||
t.Fatal("nil backend")
|
||||
}
|
||||
|
||||
// Now get a state manager and check that it fails to refresh the state
|
||||
sm, err := b.StateMgr(backend.DefaultStateName)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error fetching StateMgr with %s: %v", backend.DefaultStateName, err)
|
||||
}
|
||||
err = sm.RefreshState()
|
||||
if nil == err {
|
||||
t.Error("expected error when refreshing state without a client cert")
|
||||
} else if !strings.Contains(err.Error(), "remote error: tls: bad certificate") {
|
||||
t.Errorf("expected the error to report missing tls credentials: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSServer_WithCertPasses(t *testing.T) {
|
||||
// Ensure that the expected amount of calls is made to the server
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
mockCallback := NewMockHttpServerCallback(ctrl)
|
||||
|
||||
// Two or three (not testing the caching here) calls to GET
|
||||
mockCallback.EXPECT().
|
||||
StateGET(gomock.Any()).
|
||||
MinTimes(2).
|
||||
MaxTimes(3)
|
||||
// One call to the POST to write the data
|
||||
mockCallback.EXPECT().
|
||||
StatePOST(gomock.Any())
|
||||
|
||||
// Fire up a test server
|
||||
ts, err := NewHttpTestServer(withHttpServerCallback(mockCallback))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error creating test server: %v", err)
|
||||
}
|
||||
defer ts.Close()
|
||||
|
||||
// Configure the backend to the pre-populated sample state, and with all the test certs lined up
|
||||
url := ts.URL + "/state/sample"
|
||||
caData, err := os.ReadFile("testdata/certs/ca.cert.pem")
|
||||
if err != nil {
|
||||
t.Fatalf("error reading ca certs: %v", err)
|
||||
}
|
||||
clientCertData, err := os.ReadFile("testdata/certs/client.crt")
|
||||
if err != nil {
|
||||
t.Fatalf("error reading client cert: %v", err)
|
||||
}
|
||||
clientKeyData, err := os.ReadFile("testdata/certs/client.key")
|
||||
if err != nil {
|
||||
t.Fatalf("error reading client key: %v", err)
|
||||
}
|
||||
conf := map[string]cty.Value{
|
||||
"address": cty.StringVal(url),
|
||||
"lock_address": cty.StringVal(url),
|
||||
"unlock_address": cty.StringVal(url),
|
||||
"client_ca_certificate_pem": cty.StringVal(string(caData)),
|
||||
"client_certificate_pem": cty.StringVal(string(clientCertData)),
|
||||
"client_private_key_pem": cty.StringVal(string(clientKeyData)),
|
||||
}
|
||||
b := backend.TestBackendConfig(t, New(), configs.SynthBody("synth", conf)).(*Backend)
|
||||
if nil == b {
|
||||
t.Fatal("nil backend")
|
||||
}
|
||||
|
||||
// Now get a state manager, fetch the state, and ensure that the "foo" output is not set
|
||||
sm, err := b.StateMgr(backend.DefaultStateName)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error fetching StateMgr with %s: %v", backend.DefaultStateName, err)
|
||||
}
|
||||
if err = sm.RefreshState(); err != nil {
|
||||
t.Fatalf("unexpected error calling RefreshState: %v", err)
|
||||
}
|
||||
state := sm.State()
|
||||
if nil == state {
|
||||
t.Fatal("nil state")
|
||||
}
|
||||
stateFoo := state.OutputValue(addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance))
|
||||
if stateFoo != nil {
|
||||
t.Errorf("expected nil foo from state; got %v", stateFoo)
|
||||
}
|
||||
|
||||
// Create a new state that has "foo" set to "bar" and ensure that state is as expected
|
||||
state = states.BuildState(func(ss *states.SyncState) {
|
||||
ss.SetOutputValue(
|
||||
addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
|
||||
cty.StringVal("bar"),
|
||||
false)
|
||||
})
|
||||
stateFoo = state.OutputValue(addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance))
|
||||
if nil == stateFoo {
|
||||
t.Fatal("nil foo after building state with foo populated")
|
||||
}
|
||||
if foo := stateFoo.Value.AsString(); foo != "bar" {
|
||||
t.Errorf("Expected built state foo value to be bar; got %s", foo)
|
||||
}
|
||||
|
||||
// Ensure the change hasn't altered the current state manager state by checking "foo" and comparing states
|
||||
curState := sm.State()
|
||||
curStateFoo := curState.OutputValue(addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance))
|
||||
if curStateFoo != nil {
|
||||
t.Errorf("expected session manager state to be unaltered and still nil, but got: %v", curStateFoo)
|
||||
}
|
||||
if reflect.DeepEqual(state, curState) {
|
||||
t.Errorf("expected %v != %v; but they were equal", state, curState)
|
||||
}
|
||||
|
||||
// Write the new state, persist, and refresh
|
||||
if err = sm.WriteState(state); err != nil {
|
||||
t.Errorf("error writing state: %v", err)
|
||||
}
|
||||
if err = sm.PersistState(nil); err != nil {
|
||||
t.Errorf("error persisting state: %v", err)
|
||||
}
|
||||
if err = sm.RefreshState(); err != nil {
|
||||
t.Errorf("error refreshing state: %v", err)
|
||||
}
|
||||
|
||||
// Get the state again and verify that is now the same as state and has the "foo" value set to "bar"
|
||||
curState = sm.State()
|
||||
if !reflect.DeepEqual(state, curState) {
|
||||
t.Errorf("expected %v == %v; but they were unequal", state, curState)
|
||||
}
|
||||
curStateFoo = curState.OutputValue(addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance))
|
||||
if nil == curStateFoo {
|
||||
t.Fatal("nil foo")
|
||||
}
|
||||
if foo := curStateFoo.Value.AsString(); foo != "bar" {
|
||||
t.Errorf("expected foo to be bar, but got: %s", foo)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunServer allows running the server for local debugging; it runs until ctl-c is received
|
||||
func TestRunServer(t *testing.T) {
|
||||
if _, ok := os.LookupEnv("TEST_RUN_SERVER"); !ok {
|
||||
t.Skip("TEST_RUN_SERVER not set")
|
||||
}
|
||||
s, err := NewHttpTestServer()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error creating test server: %v", err)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
t.Log(s.URL)
|
||||
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||
defer cancel()
|
||||
// wait until signal
|
||||
<-ctx.Done()
|
||||
}
|
29
internal/backend/remote-state/http/testdata/certs/ca.cert.pem
vendored
Normal file
29
internal/backend/remote-state/http/testdata/certs/ca.cert.pem
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFBzCCAu+gAwIBAgIUFPfAxSWlzjWAdQAW+uDbciQm3SowDQYJKoZIhvcNAQEL
|
||||
BQAwEjEQMA4GA1UEAwwHdGVzdC5jYTAgFw0yMjEwMTMyMTE4MTlaGA8zMDIyMDIx
|
||||
MzIxMTgxOVowEjEQMA4GA1UEAwwHdGVzdC5jYTCCAiIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggIPADCCAgoCggIBAJUdKvIM9q7H8TLqj0O6qHUnbE0N3dnNNGVtyO7Nkn4t7urx
|
||||
X4qmQ6nMzKlC5YhGIlOKO4X0kPXf623+bP+jUf9qAFLkx5SK9TDerhh3e9y9+0YY
|
||||
C+CM8bQdJD7jFN1oOcKTJipNbjVXCqWqrBXJg91v3p4kyUvGUv05d3pU9nQvKd7R
|
||||
BGdWh68hjPFqdFso+A1ggxwJ4pEQCllxLu60RpRFwPoup/BeblPz9f3voeqhxT1J
|
||||
RLviG6HhpMxh44qNh8UrWGyaAk2C5c0rghBUHdfx/RgP2cYuUo5fhPYOHhO0lX80
|
||||
0LebXA6nwOhVeHNvrRfjEJS3tTWaFXyaOUiJT2QX2nG0i6cx6pS8dLMMSFLjMSX6
|
||||
bTH3KtTR+UrOfC3B47FOO5U++EnBg3WiZCKp+i8+5Sc3MjTw4B8cmydYr59hNWrk
|
||||
8zrfG1uE6WvxKg1bRc1FcixERcLnIbRH6LE3hHXzYlLoJ8+q9zP0EGqGHycSlv+C
|
||||
E+6QMMKU0u2tHnixqhlt79ad6bpC52VS3lFt3Fh/TEKWjS1rn2hYZKGSymJpbPFn
|
||||
q1RQZcxZWjKjqi5UEuAVGfBc4+HLZHq2Vq9umjLn0nuVixjBeBsCBaFC/amksFEJ
|
||||
fAmMXDERO7Hb4vePq1t9iusWrRPhkvZt6R1Pozg1Ls+xSJQE09n3jWd0/fMhAgMB
|
||||
AAGjUzBRMB0GA1UdDgQWBBSe+CLJRDjlHurYVRcXvhXyohcVdDAfBgNVHSMEGDAW
|
||||
gBSe+CLJRDjlHurYVRcXvhXyohcVdDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
|
||||
DQEBCwUAA4ICAQBluWhlAuG7CfMP31aJzl9AucHHLwfAECKg35XTPiF+YrL7rcbQ
|
||||
0dQyErCXyx7lLGEMqfNxVW48JtLCAATAZk3PwaQdU5OTcKA6Q/mQJwagfgmCVC5+
|
||||
Y4fdc7HhfOkGCOQ7aqyJ/EmygafgShreNimRDgIFomEs2hEEKAfvq2YBKcfcDyS7
|
||||
vCJZgzKoDmFe4DJjnYN/Gmj/4ak1kwtkoTkwdBlK+zWfbWHSUweXjCvbPPhKCPfy
|
||||
3Vu++BIW7402aLsP4xyQY/HPGErV3l1TpY3FdCENGQXANF/gPDWj/Q92OdTMRL0U
|
||||
XXSshNT3YjCxUH3M4A07A11TQwXZRFs2AkZyjJ6M5XNd36FswHh7fSjNLThU6h2V
|
||||
dI0y/rU4y24KG7KeUayTE1HLGGDskZdXSOL2vH/MTvpheKnLE8fQrKb/SgY+l9RA
|
||||
fIKwjDfMSL11luuSUIdevt5CEGFms8hpLU1RG2z/qSYz3If/dhN6YdiFJ54Qhjw9
|
||||
J5UO4eucsCm3MmsX2jUsDUIjHu92Rt7a3N21lVwzAifwwUzlDrY5xFrtpdhiSEAd
|
||||
HFmIQOEr3C9xqD3v3b/4N9SoOjZS2j4xk+GQ8XZeTDYf8ZlkXvXHWwEHbVqj0toe
|
||||
WDooC6oivNJAEs2GxJpyLmmfxIbRjE1sdmVZtmlSb3hY0Rme1SF9FoyZDw==
|
||||
-----END CERTIFICATE-----
|
52
internal/backend/remote-state/http/testdata/certs/ca.key
vendored
Normal file
52
internal/backend/remote-state/http/testdata/certs/ca.key
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
g3yddc0Zj29o1jw56J043a37q1CmmsI=
|
||||
-----END PRIVATE KEY-----
|
29
internal/backend/remote-state/http/testdata/certs/client.crt
vendored
Normal file
29
internal/backend/remote-state/http/testdata/certs/client.crt
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFCzCCAvOgAwIBAgIUJsntRGo85J+ZJAb73snhKsM1oVowDQYJKoZIhvcNAQEL
|
||||
BQAwEjEQMA4GA1UEAwwHdGVzdC5jYTAgFw0yMjEwMTMyMTE4NDBaGA8zMDIyMDIx
|
||||
MzIxMTg0MFowFjEUMBIGA1UEAwwLdGVzdC5jbGllbnQwggIiMA0GCSqGSIb3DQEB
|
||||
AQUAA4ICDwAwggIKAoICAQCUQebHvDL2ksHcNh6hw0xMCbPxwrBd+qQVFGf/2wL3
|
||||
Dk8Ls/NgKQqkoG4WPi4vIuu277+7ngqUZcFbDL/MO7uAWlzthFkhI8IyXeB8t+cj
|
||||
liqwdgfRFLvoae1PG6ZoFrTXgOsW3tW8SRC8Kax7RdJjEMU1yWEC6OwiH/gabqZM
|
||||
+i2qSwOgPnxAalljbWDJU0kj+zRfw35W4L/Q9quMid8KQYE71wQoiiBFYFcx552c
|
||||
kL30xEpKat5ffB42sBpDzO3S/dM0k36im3wEFJHaEW2q4+0Ns9/PQ2OxIfoRC+lD
|
||||
qYVPeljNSK2n+PSZDjswpZtqK68RD0AM0PmuPqV7Q2DPGoCXpwcq3lczlFH69T7z
|
||||
s7izG8cnmyi9eWiXgPFWG5JzyeQi2P5fMumF1UVpG2NHyDyEGfXME8dh4S6BpAUJ
|
||||
9BAXjatjzA5bq4CGS1w/pFrUvhiVQY7byGDqrtTiDa1f48T2CkvVmRUIiKlrvnDe
|
||||
ezCnJ6P28D0yISyJLN45sQhuyw5idaXHl2AsvDRDFj2iZ/WhY7tCf0O/DSCuI1uZ
|
||||
WcFXHdRFn9RoGuUqy97+6rPZaB+xNnx83O9pG+Hrx2iz2pSD/pb0b9xKH5VvN1pN
|
||||
JjtaoMXod1+2z8XdTUzPvkeZyDXIasaZwmSEOOZmGgoRe+KE4ZBlk4XBlm5p2Q6U
|
||||
RwIDAQABo1MwUTAPBgNVHREECDAGhwR/AAABMB0GA1UdDgQWBBQ/5KcOS58ZKYth
|
||||
wRpJ+VKCcwJdpTAfBgNVHSMEGDAWgBSe+CLJRDjlHurYVRcXvhXyohcVdDANBgkq
|
||||
hkiG9w0BAQsFAAOCAgEABiy0c+7T7dam8IjejbDlamAMvDCWFoVW+mLjsGwaS7vx
|
||||
jmtGig5E08q7axf32iAkfwzi/vEwt66uWGVctUm6/EqH2XvlqZXcsMGiAuWYwJ2Q
|
||||
DXowHlcIoIRC958qA+6cCAdxoUnTpYSdWWMR+QZ9XDB9MaAZJ+zKhb8nEETl9jGR
|
||||
Z9iaSEnupposxt5NMvNUU8dTjjjv430WvZnvZaTvegLIQ5QaHeECUQ61Nm18tEey
|
||||
cPiMu2TN8uO4m67lj4kyXaS3wD7zNuZph55g4vNbQrffTEHUZSFqrr1fyG+7Y+fb
|
||||
F9hzbhqBgCnYQ5JaxtVbqFAvwDFWRoq2G9gARi/Yuf34djoP09IZvbRymZWJ5857
|
||||
KRCT6mBestfOzu2oIz6lDO44fFiejOTDCSDHZ2Try3xAsqS4LAZjWNSqfBIJwABi
|
||||
bNTWV2yxtlnqEkaPtGYSwQLdF8MTBRbxzsiELktgdgt7XcfarhEKj9iHWirEt0Cw
|
||||
POnl8S8GzwpsSAomijlLhfyU0J1+p6UP0zJE4YOjKZFv5ddmBCeSTwj0gwVSsSNg
|
||||
ff7T7IvkTcIMZUlrskeMY4svXpI5FeG+sXXNp2J/iz4XIQdcdpB3t+fDCUcic9Fq
|
||||
ILJKT1sQpjv4gyAO2BJd4D7clUJwDC059+dh3dDC9d51uHvCra2F/+FGeodQRuU=
|
||||
-----END CERTIFICATE-----
|
27
internal/backend/remote-state/http/testdata/certs/client.csr
vendored
Normal file
27
internal/backend/remote-state/http/testdata/certs/client.csr
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIEfTCCAmUCAQAwFjEUMBIGA1UEAwwLdGVzdC5jbGllbnQwggIiMA0GCSqGSIb3
|
||||
DQEBAQUAA4ICDwAwggIKAoICAQCUQebHvDL2ksHcNh6hw0xMCbPxwrBd+qQVFGf/
|
||||
2wL3Dk8Ls/NgKQqkoG4WPi4vIuu277+7ngqUZcFbDL/MO7uAWlzthFkhI8IyXeB8
|
||||
t+cjliqwdgfRFLvoae1PG6ZoFrTXgOsW3tW8SRC8Kax7RdJjEMU1yWEC6OwiH/ga
|
||||
bqZM+i2qSwOgPnxAalljbWDJU0kj+zRfw35W4L/Q9quMid8KQYE71wQoiiBFYFcx
|
||||
552ckL30xEpKat5ffB42sBpDzO3S/dM0k36im3wEFJHaEW2q4+0Ns9/PQ2OxIfoR
|
||||
C+lDqYVPeljNSK2n+PSZDjswpZtqK68RD0AM0PmuPqV7Q2DPGoCXpwcq3lczlFH6
|
||||
9T7zs7izG8cnmyi9eWiXgPFWG5JzyeQi2P5fMumF1UVpG2NHyDyEGfXME8dh4S6B
|
||||
pAUJ9BAXjatjzA5bq4CGS1w/pFrUvhiVQY7byGDqrtTiDa1f48T2CkvVmRUIiKlr
|
||||
vnDeezCnJ6P28D0yISyJLN45sQhuyw5idaXHl2AsvDRDFj2iZ/WhY7tCf0O/DSCu
|
||||
I1uZWcFXHdRFn9RoGuUqy97+6rPZaB+xNnx83O9pG+Hrx2iz2pSD/pb0b9xKH5Vv
|
||||
N1pNJjtaoMXod1+2z8XdTUzPvkeZyDXIasaZwmSEOOZmGgoRe+KE4ZBlk4XBlm5p
|
||||
2Q6URwIDAQABoCIwIAYJKoZIhvcNAQkOMRMwETAPBgNVHREECDAGhwR/AAABMA0G
|
||||
CSqGSIb3DQEBCwUAA4ICAQAFUKmXAcULGC1idSXVWRnhzzr6qnl4K2QZVse8kNsk
|
||||
BD+ePZp7/jc9URP+ykFhVHc1gOy0VgvNm6qePS9ccPTQrRxmXUmMrV2ead9z4h4O
|
||||
OnnIyfxLxO+Kd1lJ/1UU8CNs3tDQnxEvtx1hYBIDNsyB4bAsfGVBGzBrsoHEjZOg
|
||||
zTvvPEnH/GpnEITTwK9J6tZ2zanE0K5z2NcSHPjzO0z92sAkcfTIZovcsVCGR3j4
|
||||
UDBMWAgK9vybG5G6taQyducU7/kMLcEP5ayG0qIeIrS2GRmOqSixAQQ+Qk6Ucs4w
|
||||
HD3/9oue5vWJEG0j86jEchdg3OCbHbQEje8Bf39xhpICel45EdGsxc61kiB/c5Lu
|
||||
8kYQTXDr9P1wtAag5XLmv/nf6pzlQ+LthU/2/EH0r948Rj2Yz4HOOHsfPuB/izF8
|
||||
NTAH/VBgp2c/VRjEYd0YQ4X3AS+Q8BwBeR8+OUJu97AIWnM8kjTcRa1ybCGMkQ3L
|
||||
IjGWgIYnICEmiEJhLo/y7jMSdRwUT9g5zz3koqChzeFSU1LuH/yE2B6GfneblDK+
|
||||
B7WDOkUEbHfJ5q0TZwWEgQdpcY5OH+o78NfJpTvgNtPV3B83+g+DdAW2jtgMZ6do
|
||||
Rb7V+uPvbU9VC2Ng7jacewMtfM3PKugIZ034UUjebQ7/N5ZD01xuJKOG/w2LuUGh
|
||||
GQ==
|
||||
-----END CERTIFICATE REQUEST-----
|
52
internal/backend/remote-state/http/testdata/certs/client.key
vendored
Normal file
52
internal/backend/remote-state/http/testdata/certs/client.key
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
SXbUSo1aOU/ZWOnVKdyjhPBcPZMEqQ==
|
||||
-----END PRIVATE KEY-----
|
29
internal/backend/remote-state/http/testdata/certs/server.crt
vendored
Normal file
29
internal/backend/remote-state/http/testdata/certs/server.crt
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFCzCCAvOgAwIBAgIUEJ4OCw9X1j5TegymXZENMgfdBZcwDQYJKoZIhvcNAQEL
|
||||
BQAwEjEQMA4GA1UEAwwHdGVzdC5jYTAgFw0yMjEwMTMyMTE4MzBaGA8zMDIyMDIx
|
||||
MzIxMTgzMFowFjEUMBIGA1UEAwwLdGVzdC5zZXJ2ZXIwggIiMA0GCSqGSIb3DQEB
|
||||
AQUAA4ICDwAwggIKAoICAQDBTTBoca0tn2EAxbQLXw1diEH5+YltZUFz5gH3aSDf
|
||||
H+uKame4iFsPybsUstmUqy3D9ZTzjNcauAhB75+RgePn4D0/qePPjdsFz11jxacA
|
||||
AMkg/mPLPtrkEAiRzvSXXoYN1Gq6uNdGricyKGtSKzqQh158W2ZfLKUKvgGlQ8RD
|
||||
3RFsFanQS6aiNwPgFK1SeFFt4wTJbtpvKNpJSe/XDDmkyMIN6/pVRo56v2PvsERA
|
||||
mUQJ+blyhOy7Egt0/uF7JUklzLIi5eKjv2JpcVwH83OAovKl1vy2mfiCZSjCwQeB
|
||||
ahnWgAaAaJir7uOVNDNXI4qM/KySKN7Nfyo+9sRuNBjMb5b0N8s70YIAyzoylJ0U
|
||||
E8x+a7XyMJlPvpARGXuNSDwR9rRytpGZIeMPcO1YQh9+V5k7il6/70thNYW5/Cb0
|
||||
PsHU5XOSlmOsOLcr1JaD2YTJJflVyhrPwMSAphRuUCFuyQinnHi59Rk2rNuTj/R3
|
||||
dFrSqtcfnvjbc+1KbyDFpnyf40W/EPmS4mF3UPRD4oRsvXpy85E25uh5Q+R4MMdd
|
||||
g3KHsZ+SiObUBa33kd9rG6peJz0cvkJIhBzbJcXPzN2EMgow2C5MYKjmNXclYWIH
|
||||
ypkFSo6OxFHhIQdeh3Ga7pZqJaOVUA8wm2olIjRQgQFJjRRc6KU2w95lJlFvHXlW
|
||||
0QIDAQABo1MwUTAPBgNVHREECDAGhwR/AAABMB0GA1UdDgQWBBQpv1S2rSSjgJ7a
|
||||
xONcLKxYRE3qJzAfBgNVHSMEGDAWgBSe+CLJRDjlHurYVRcXvhXyohcVdDANBgkq
|
||||
hkiG9w0BAQsFAAOCAgEASpVE6Pj/sPf5heCDI8miF3Xw65BkLMCCL4ZUOugtK0Hg
|
||||
dbcnaMd6Hwf+mEs/2jaD+2xah489fX4KynJnQ68VpnTMT4yYcsEfvwmZA7Bqo/Ef
|
||||
MwyFJe/E+Y1mAu7KQodLZ1E13cGVQKDQVwQ5ueyRD3C0bY3glMKfnXvnIIEMiSCg
|
||||
UTAstj4Z0h9KYrVSRRVfCGOtlvFPo8jg+yPVPsDqGHn2hOH+FYoHv8V1/gGrXJTe
|
||||
HcTHFIAIkBefHAXCaCYYq3Qfp/ZBpuT5N4bwQtHKmgv5hhyy0kaZRFfE98WkGdSk
|
||||
Yg5wZRIX6UbjPdyiEnhQdOrnGDehKf9iwv1q98B9hgXzEzdK0e3bR8UY2MRvs/Vz
|
||||
L2BBDkJHsTo9P1q6zAsmfVNhQPGrEH2pDir8yYpXPz/ocZa7GghJ/RPrYirVTHZp
|
||||
fNxoMkNfgfVQpSsFvvI/fMGfhG65TQJdq82rAJ5tRRRs69uA00NCggKRWmEdVYpV
|
||||
jWuMiLrE5U2tHruMytM/ek6kjhzmNpJgPG2alsJHgVb5G8elcCuC0Dx5HjnwbR60
|
||||
8V1v2z5kgU9dkT05vZ5RPmNyuv+VP+8Qx/NPCMrf1SaQffW4PaP3YUaRwzJYzEP/
|
||||
ZDUOmPsgUMLwj/jT3sEkSc1qUByui2A0QJk2dQzcbNfvpWoBQ+q7m2OHkmzXZCc=
|
||||
-----END CERTIFICATE-----
|
27
internal/backend/remote-state/http/testdata/certs/server.csr
vendored
Normal file
27
internal/backend/remote-state/http/testdata/certs/server.csr
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIEfTCCAmUCAQAwFjEUMBIGA1UEAwwLdGVzdC5zZXJ2ZXIwggIiMA0GCSqGSIb3
|
||||
DQEBAQUAA4ICDwAwggIKAoICAQDBTTBoca0tn2EAxbQLXw1diEH5+YltZUFz5gH3
|
||||
aSDfH+uKame4iFsPybsUstmUqy3D9ZTzjNcauAhB75+RgePn4D0/qePPjdsFz11j
|
||||
xacAAMkg/mPLPtrkEAiRzvSXXoYN1Gq6uNdGricyKGtSKzqQh158W2ZfLKUKvgGl
|
||||
Q8RD3RFsFanQS6aiNwPgFK1SeFFt4wTJbtpvKNpJSe/XDDmkyMIN6/pVRo56v2Pv
|
||||
sERAmUQJ+blyhOy7Egt0/uF7JUklzLIi5eKjv2JpcVwH83OAovKl1vy2mfiCZSjC
|
||||
wQeBahnWgAaAaJir7uOVNDNXI4qM/KySKN7Nfyo+9sRuNBjMb5b0N8s70YIAyzoy
|
||||
lJ0UE8x+a7XyMJlPvpARGXuNSDwR9rRytpGZIeMPcO1YQh9+V5k7il6/70thNYW5
|
||||
/Cb0PsHU5XOSlmOsOLcr1JaD2YTJJflVyhrPwMSAphRuUCFuyQinnHi59Rk2rNuT
|
||||
j/R3dFrSqtcfnvjbc+1KbyDFpnyf40W/EPmS4mF3UPRD4oRsvXpy85E25uh5Q+R4
|
||||
MMddg3KHsZ+SiObUBa33kd9rG6peJz0cvkJIhBzbJcXPzN2EMgow2C5MYKjmNXcl
|
||||
YWIHypkFSo6OxFHhIQdeh3Ga7pZqJaOVUA8wm2olIjRQgQFJjRRc6KU2w95lJlFv
|
||||
HXlW0QIDAQABoCIwIAYJKoZIhvcNAQkOMRMwETAPBgNVHREECDAGhwR/AAABMA0G
|
||||
CSqGSIb3DQEBCwUAA4ICAQA5BmbXy/UXXNXe0WHR1gxx5nwmJ1CyNy+efVq4cl8Z
|
||||
ltxaTWy8IZOGN3YHY2ZhmKccm7ecNq1Kv9FUctPe6+97HXb2rL0rB0gO1AyxWJKU
|
||||
edzls63/0n+AnQqwnPQdgL9N5vIw/0avLo3U8F+kI5hbYfG7fvw3zHdJIMiLTRsn
|
||||
qKvkF2TMBxr06nrlJsQqG90k9xS3iX7DqssDq3niVgAwP2NbS2wDXk7/6R40LNx9
|
||||
RzFHDyHplF/3ySjctkx7kkAPdamGr8NNs7kQkVZGKmD25V7i5ggoGx9lo3AiBbmT
|
||||
9Keac43vhlC4Bj9zW2O6Ih9TP9sDhp6iA4NtdNnK9tfn59Av6J4pB6EhMzaLtu4J
|
||||
jqc5b3+Wvq1xv0Sm2Y+JjuawT7jgrT4vnSEqqkFTTV6igzctatOCxz4ejl3Q2sD0
|
||||
OjlArZWX9kY2yyuFt6LhlM3We0IDUQjEf0JtA9EFixbm+ieHbPEFHFiD0w9uN/VI
|
||||
cYzxnubGgvv2wN1N+YHNRFFOWyT+Ty7Hp0Kz3dh8g+DY4vxvsfG6XfnvPT5StSKd
|
||||
ACEfl8HoSET/qJZIkuIhErzzUNNK4+4QzQav7auZUQUrdK6P+rryE3lZauZ3rV+9
|
||||
ZXWT3PG1qHuWNNriTrC6n4tpa8m5UkZMdeoK2pS3y3SLDCJJV7Q3WHCZEVddIPdV
|
||||
Ew==
|
||||
-----END CERTIFICATE REQUEST-----
|
52
internal/backend/remote-state/http/testdata/certs/server.key
vendored
Normal file
52
internal/backend/remote-state/http/testdata/certs/server.key
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
+AXVqLYxuaMTIdm5Ahyl1sCNrOl8nQ==
|
||||
-----END PRIVATE KEY-----
|
30
internal/backend/remote-state/http/testdata/gencerts.sh
vendored
Executable file
30
internal/backend/remote-state/http/testdata/gencerts.sh
vendored
Executable file
@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Generates certs required for mTLS testing:
|
||||
# - ca.key and ca.cert.pem are self-signed, used as the source of truth for client and server to verify each other.
|
||||
# - client.key and client.crt are the client's key and cert (signed by the ca key and cert)
|
||||
# - server.key and server.crt are the server's key and cert (signed by the ca key and cert)
|
||||
|
||||
set -ex
|
||||
|
||||
# I was doing this on M1 mac and needed newer openssl to add the SAN IP; please export OPENSSL when invoking as needed
|
||||
OPENSSL="${OPENSSL:-openssl}"
|
||||
|
||||
# Nuke and recreate the certs dir
|
||||
rm -rf certs
|
||||
mkdir certs
|
||||
cd certs || exit 1
|
||||
|
||||
# CA
|
||||
"$OPENSSL" genrsa -out ca.key 4096
|
||||
"$OPENSSL" req -new -x509 -days 365000 -key ca.key -out ca.cert.pem
|
||||
|
||||
# Server
|
||||
"$OPENSSL" genrsa -out server.key 4096
|
||||
"$OPENSSL" req -new -key server.key -out server.csr -addext 'subjectAltName = IP:127.0.0.1'
|
||||
"$OPENSSL" x509 -req -days 365000 -in server.csr -CA ca.cert.pem -CAkey ca.key -CAcreateserial -out server.crt -copy_extensions copy
|
||||
|
||||
# Client
|
||||
"$OPENSSL" genrsa -out client.key 4096
|
||||
"$OPENSSL" req -new -key client.key -out client.csr -addext 'subjectAltName = IP:127.0.0.1'
|
||||
"$OPENSSL" x509 -req -days 365000 -in client.csr -CA ca.cert.pem -CAkey ca.key -CAcreateserial -out client.crt -copy_extensions copy
|
@ -790,18 +790,21 @@ func TestApply_plan_remoteState(t *testing.T) {
|
||||
|
||||
_, snap := testModuleWithSnapshot(t, "apply")
|
||||
backendConfig := cty.ObjectVal(map[string]cty.Value{
|
||||
"address": cty.StringVal(srv.URL),
|
||||
"update_method": cty.NullVal(cty.String),
|
||||
"lock_address": cty.NullVal(cty.String),
|
||||
"unlock_address": cty.NullVal(cty.String),
|
||||
"lock_method": cty.NullVal(cty.String),
|
||||
"unlock_method": cty.NullVal(cty.String),
|
||||
"username": cty.NullVal(cty.String),
|
||||
"password": cty.NullVal(cty.String),
|
||||
"skip_cert_verification": cty.NullVal(cty.Bool),
|
||||
"retry_max": cty.NullVal(cty.String),
|
||||
"retry_wait_min": cty.NullVal(cty.String),
|
||||
"retry_wait_max": cty.NullVal(cty.String),
|
||||
"address": cty.StringVal(srv.URL),
|
||||
"update_method": cty.NullVal(cty.String),
|
||||
"lock_address": cty.NullVal(cty.String),
|
||||
"unlock_address": cty.NullVal(cty.String),
|
||||
"lock_method": cty.NullVal(cty.String),
|
||||
"unlock_method": cty.NullVal(cty.String),
|
||||
"username": cty.NullVal(cty.String),
|
||||
"password": cty.NullVal(cty.String),
|
||||
"skip_cert_verification": cty.NullVal(cty.Bool),
|
||||
"retry_max": cty.NullVal(cty.String),
|
||||
"retry_wait_min": cty.NullVal(cty.String),
|
||||
"retry_wait_max": cty.NullVal(cty.String),
|
||||
"client_ca_certificate_pem": cty.NullVal(cty.String),
|
||||
"client_certificate_pem": cty.NullVal(cty.String),
|
||||
"client_private_key_pem": cty.NullVal(cty.String),
|
||||
})
|
||||
backendConfigRaw, err := plans.NewDynamicValue(backendConfig, backendConfig.Type())
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user