mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-20 03:11:46 +00:00
refactor: migrate lbagent signing to predastore/auth.SignReq (#281)
agent.go signed gateway requests with aws-sdk-go v1's v4.Signer. Switch to predastore/auth.SignReq (a thin wrapper over aws-sdk-go-v2's v4.Signer) so the monorepo runs a single signer version and drops the last direct dependency on aws-sdk-go v1's signer subpackage. - Replace the *v4.Signer field with the raw access/secret keys. - signedPost computes the hex SHA-256 payload hash and calls auth.SignReq. - Add TestSignedPost_ProducesVerifiableSignature: the signed request parses and verifies server-side via auth.ParseReq/Verify with a matching body hash.
This commit is contained in:
+11
-10
@@ -5,7 +5,9 @@ package lbagent
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -20,8 +22,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||
"github.com/mulgadc/predastore/auth"
|
||||
"github.com/mulgadc/spinifex/internal/tlsconfig"
|
||||
)
|
||||
|
||||
@@ -43,8 +44,9 @@ type Agent struct {
|
||||
pidPath string
|
||||
socketPath string // HAProxy stats socket
|
||||
|
||||
signer *v4.Signer
|
||||
client *http.Client
|
||||
accessKey string
|
||||
secretKey string
|
||||
client *http.Client
|
||||
|
||||
localConfigHash string
|
||||
stopCh chan struct{}
|
||||
@@ -70,9 +72,6 @@ func New(lbID, gatewayURL, accessKey, secretKey, region string) (*Agent, error)
|
||||
return nil, fmt.Errorf("region is required")
|
||||
}
|
||||
|
||||
creds := credentials.NewStaticCredentials(accessKey, secretKey, "")
|
||||
signer := v4.NewSigner(creds)
|
||||
|
||||
// Use system CA trust store (CA cert injected via cloud-init ca_certs).
|
||||
client := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
@@ -93,7 +92,8 @@ func New(lbID, gatewayURL, accessKey, secretKey, region string) (*Agent, error)
|
||||
configPath: DefaultConfigPath,
|
||||
pidPath: DefaultPIDPath,
|
||||
socketPath: fmt.Sprintf("/tmp/spinifex-haproxy/lb-%s.sock", lbID),
|
||||
signer: signer,
|
||||
accessKey: accessKey,
|
||||
secretKey: secretKey,
|
||||
client: client,
|
||||
stopCh: make(chan struct{}),
|
||||
reloadFn: reloadHAProxy,
|
||||
@@ -238,8 +238,9 @@ func (a *Agent) signedPost(params url.Values) ([]byte, error) {
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
_, err = a.signer.Sign(req, bytes.NewReader([]byte(body)), "elasticloadbalancing", a.region, time.Now())
|
||||
if err != nil {
|
||||
sum := sha256.Sum256([]byte(body))
|
||||
payloadHash := hex.EncodeToString(sum[:])
|
||||
if err := auth.SignReq(req, a.accessKey, a.secretKey, payloadHash, "elasticloadbalancing", a.region); err != nil {
|
||||
return nil, fmt.Errorf("sign request: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
package lbagent
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mulgadc/predastore/auth"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
@@ -68,6 +74,53 @@ func TestNew_SocketPath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSignedPost_ProducesVerifiableSignature confirms the migrated signing path
|
||||
// (predastore/auth.SignReq over aws-sdk-go-v2) produces a request the gateway's
|
||||
// SigV4 verifier accepts, including a body-hash that matches X-Amz-Content-Sha256.
|
||||
func TestSignedPost_ProducesVerifiableSignature(t *testing.T) {
|
||||
const (
|
||||
accessKey = "AKIAIOSFODNN7EXAMPLE"
|
||||
secretKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
|
||||
region = "us-east-1"
|
||||
)
|
||||
|
||||
var parsed bool
|
||||
var verifyErr error
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
sum := sha256.Sum256(body)
|
||||
req, err := auth.ParseReq(r)
|
||||
if err != nil {
|
||||
verifyErr = err
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
parsed = true
|
||||
verifyErr = req.Verify(secretKey, "elasticloadbalancing", region,
|
||||
auth.WithBodyHash(hex.EncodeToString(sum[:])))
|
||||
fmt.Fprint(w, "ok")
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
agent, err := New("lb-sig", srv.URL, accessKey, secretKey, region)
|
||||
if err != nil {
|
||||
t.Fatalf("New: %v", err)
|
||||
}
|
||||
|
||||
if _, err := agent.signedPost(url.Values{
|
||||
"Action": {"LBAgentHeartbeat"},
|
||||
"LoadBalancerId": {"lb-sig"},
|
||||
}); err != nil {
|
||||
t.Fatalf("signedPost: %v", err)
|
||||
}
|
||||
if !parsed {
|
||||
t.Fatal("gateway did not parse a SigV4 Authorization header")
|
||||
}
|
||||
if verifyErr != nil {
|
||||
t.Fatalf("signed request failed server-side verification: %v", verifyErr)
|
||||
}
|
||||
}
|
||||
|
||||
// fakeGateway returns a test server that responds to LBAgentHeartbeat and GetLBConfig.
|
||||
func fakeGateway(t *testing.T, configHash, configText, status string) *httptest.Server {
|
||||
t.Helper()
|
||||
|
||||
Reference in New Issue
Block a user