aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkegsay <kegan@matrix.org>2022-02-01 16:36:17 +0000
committerGitHub <noreply@github.com>2022-02-01 16:36:17 +0000
commita09d71d231861f8825a4f8f1dfd79311c4c236a6 (patch)
tree23768a595cc4972ec63ddf74c66a2605fac61e74
parent9ada4578e36b367c53057c9ee32d044e2ba26395 (diff)
Support CA certificates in CI (#2136)
* Support CA setting in generate-keys * Set DNS names correctly * Use generate-config -server not sed
-rw-r--r--build/scripts/Complement.Dockerfile10
-rw-r--r--cmd/generate-config/main.go2
-rw-r--r--cmd/generate-keys/main.go20
-rw-r--r--internal/test/config.go93
4 files changed, 105 insertions, 20 deletions
diff --git a/build/scripts/Complement.Dockerfile b/build/scripts/Complement.Dockerfile
index 55b381ba..401695ab 100644
--- a/build/scripts/Complement.Dockerfile
+++ b/build/scripts/Complement.Dockerfile
@@ -12,10 +12,14 @@ COPY . .
RUN go build ./cmd/dendrite-monolith-server
RUN go build ./cmd/generate-keys
RUN go build ./cmd/generate-config
-RUN ./generate-config --ci > dendrite.yaml
-RUN ./generate-keys --private-key matrix_key.pem --tls-cert server.crt --tls-key server.key
+RUN ./generate-keys --private-key matrix_key.pem
ENV SERVER_NAME=localhost
EXPOSE 8008 8448
-CMD sed -i "s/server_name: localhost/server_name: ${SERVER_NAME}/g" dendrite.yaml && ./dendrite-monolith-server --tls-cert server.crt --tls-key server.key --config dendrite.yaml
+# At runtime, generate TLS cert based on the CA now mounted at /ca
+# At runtime, replace the SERVER_NAME with what we are told
+CMD ./generate-keys --server $SERVER_NAME --tls-cert server.crt --tls-key server.key --tls-authority-cert /ca/ca.crt --tls-authority-key /ca/ca.key && \
+ ./generate-config -server $SERVER_NAME --ci > dendrite.yaml && \
+ cp /ca/ca.crt /usr/local/share/ca-certificates/ && update-ca-certificates && \
+ ./dendrite-monolith-server --tls-cert server.crt --tls-key server.key --config dendrite.yaml
diff --git a/cmd/generate-config/main.go b/cmd/generate-config/main.go
index a79470d8..60729672 100644
--- a/cmd/generate-config/main.go
+++ b/cmd/generate-config/main.go
@@ -83,7 +83,7 @@ func main() {
if *defaultsForCI {
cfg.AppServiceAPI.DisableTLSValidation = true
cfg.ClientAPI.RateLimiting.Enabled = false
- cfg.FederationAPI.DisableTLSValidation = true
+ cfg.FederationAPI.DisableTLSValidation = false
// don't hit matrix.org when running tests!!!
cfg.FederationAPI.KeyPerspectives = config.KeyPerspectives{}
cfg.MSCs.MSCs = []string{"msc2836", "msc2946", "msc2444", "msc2753"}
diff --git a/cmd/generate-keys/main.go b/cmd/generate-keys/main.go
index 743109f1..bddf219d 100644
--- a/cmd/generate-keys/main.go
+++ b/cmd/generate-keys/main.go
@@ -32,9 +32,12 @@ Arguments:
`
var (
- tlsCertFile = flag.String("tls-cert", "", "An X509 certificate file to generate for use for TLS")
- tlsKeyFile = flag.String("tls-key", "", "An RSA private key file to generate for use for TLS")
- privateKeyFile = flag.String("private-key", "", "An Ed25519 private key to generate for use for object signing")
+ tlsCertFile = flag.String("tls-cert", "", "An X509 certificate file to generate for use for TLS")
+ tlsKeyFile = flag.String("tls-key", "", "An RSA private key file to generate for use for TLS")
+ privateKeyFile = flag.String("private-key", "", "An Ed25519 private key to generate for use for object signing")
+ authorityCertFile = flag.String("tls-authority-cert", "", "Optional: Create TLS certificate/keys based on this CA authority. Useful for integration testing.")
+ authorityKeyFile = flag.String("tls-authority-key", "", "Optional: Create TLS certificate/keys based on this CA authority. Useful for integration testing.")
+ serverName = flag.String("server", "", "Optional: Create TLS certificate/keys with this domain name set. Useful for integration testing.")
)
func main() {
@@ -54,8 +57,15 @@ func main() {
if *tlsCertFile == "" || *tlsKeyFile == "" {
log.Fatal("Zero or both of --tls-key and --tls-cert must be supplied")
}
- if err := test.NewTLSKey(*tlsKeyFile, *tlsCertFile); err != nil {
- panic(err)
+ if *authorityCertFile == "" && *authorityKeyFile == "" {
+ if err := test.NewTLSKey(*tlsKeyFile, *tlsCertFile); err != nil {
+ panic(err)
+ }
+ } else {
+ // generate the TLS cert/key based on the authority given.
+ if err := test.NewTLSKeyWithAuthority(*serverName, *tlsKeyFile, *tlsCertFile, *authorityKeyFile, *authorityCertFile); err != nil {
+ panic(err)
+ }
}
fmt.Printf("Created TLS cert file: %s\n", *tlsCertFile)
fmt.Printf("Created TLS key file: %s\n", *tlsKeyFile)
diff --git a/internal/test/config.go b/internal/test/config.go
index bb2f8a4c..4fb6a946 100644
--- a/internal/test/config.go
+++ b/internal/test/config.go
@@ -20,6 +20,7 @@ import (
"crypto/x509"
"encoding/base64"
"encoding/pem"
+ "errors"
"fmt"
"io/ioutil"
"math/big"
@@ -158,11 +159,10 @@ func NewMatrixKey(matrixKeyPath string) (err error) {
const certificateDuration = time.Hour * 24 * 365 * 10
-// NewTLSKey generates a new RSA TLS key and certificate and writes it to a file.
-func NewTLSKey(tlsKeyPath, tlsCertPath string) error {
+func generateTLSTemplate(dnsNames []string) (*rsa.PrivateKey, *x509.Certificate, error) {
priv, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
- return err
+ return nil, nil, err
}
notBefore := time.Now()
@@ -170,7 +170,7 @@ func NewTLSKey(tlsKeyPath, tlsCertPath string) error {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
- return err
+ return nil, nil, err
}
template := x509.Certificate{
@@ -180,20 +180,21 @@ func NewTLSKey(tlsKeyPath, tlsCertPath string) error {
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
+ DNSNames: dnsNames,
}
- derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
- if err != nil {
- return err
- }
+ return priv, &template, nil
+}
+
+func writeCertificate(tlsCertPath string, derBytes []byte) error {
certOut, err := os.Create(tlsCertPath)
if err != nil {
return err
}
defer certOut.Close() // nolint: errcheck
- if err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
- return err
- }
+ return pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
+}
+func writePrivateKey(tlsKeyPath string, priv *rsa.PrivateKey) error {
keyOut, err := os.OpenFile(tlsKeyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
@@ -205,3 +206,73 @@ func NewTLSKey(tlsKeyPath, tlsCertPath string) error {
})
return err
}
+
+// NewTLSKey generates a new RSA TLS key and certificate and writes it to a file.
+func NewTLSKey(tlsKeyPath, tlsCertPath string) error {
+ priv, template, err := generateTLSTemplate(nil)
+ if err != nil {
+ return err
+ }
+
+ // Self-signed certificate: template == parent
+ derBytes, err := x509.CreateCertificate(rand.Reader, template, template, &priv.PublicKey, priv)
+ if err != nil {
+ return err
+ }
+
+ if err = writeCertificate(tlsCertPath, derBytes); err != nil {
+ return err
+ }
+ return writePrivateKey(tlsKeyPath, priv)
+}
+
+func NewTLSKeyWithAuthority(serverName, tlsKeyPath, tlsCertPath, authorityKeyPath, authorityCertPath string) error {
+ priv, template, err := generateTLSTemplate([]string{serverName})
+ if err != nil {
+ return err
+ }
+
+ // load the authority key
+ dat, err := ioutil.ReadFile(authorityKeyPath)
+ if err != nil {
+ return err
+ }
+ block, _ := pem.Decode([]byte(dat))
+ if block == nil || block.Type != "RSA PRIVATE KEY" {
+ return errors.New("authority .key is not a valid pem encoded rsa private key")
+ }
+ authorityPriv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ return err
+ }
+
+ // load the authority certificate
+ dat, err = ioutil.ReadFile(authorityCertPath)
+ if err != nil {
+ return err
+ }
+ block, _ = pem.Decode([]byte(dat))
+ if block == nil || block.Type != "CERTIFICATE" {
+ return errors.New("authority .crt is not a valid pem encoded x509 cert")
+ }
+ var caCerts []*x509.Certificate
+ caCerts, err = x509.ParseCertificates(block.Bytes)
+ if err != nil {
+ return err
+ }
+ if len(caCerts) != 1 {
+ return errors.New("authority .crt contains none or more than one cert")
+ }
+ authorityCert := caCerts[0]
+
+ // Sign the new certificate using the authority's key/cert
+ derBytes, err := x509.CreateCertificate(rand.Reader, template, authorityCert, &priv.PublicKey, authorityPriv)
+ if err != nil {
+ return err
+ }
+
+ if err = writeCertificate(tlsCertPath, derBytes); err != nil {
+ return err
+ }
+ return writePrivateKey(tlsKeyPath, priv)
+}