mirror of
https://github.com/matrix-org/dendrite
synced 2024-11-10 07:04:24 +00:00
Support CA certificates in CI (#2136)
* Support CA setting in generate-keys * Set DNS names correctly * Use generate-config -server not sed
This commit is contained in:
parent
9ada4578e3
commit
a09d71d231
4 changed files with 105 additions and 20 deletions
|
@ -12,10 +12,14 @@ COPY . .
|
||||||
RUN go build ./cmd/dendrite-monolith-server
|
RUN go build ./cmd/dendrite-monolith-server
|
||||||
RUN go build ./cmd/generate-keys
|
RUN go build ./cmd/generate-keys
|
||||||
RUN go build ./cmd/generate-config
|
RUN go build ./cmd/generate-config
|
||||||
RUN ./generate-config --ci > dendrite.yaml
|
RUN ./generate-keys --private-key matrix_key.pem
|
||||||
RUN ./generate-keys --private-key matrix_key.pem --tls-cert server.crt --tls-key server.key
|
|
||||||
|
|
||||||
ENV SERVER_NAME=localhost
|
ENV SERVER_NAME=localhost
|
||||||
EXPOSE 8008 8448
|
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
|
||||||
|
|
|
@ -83,7 +83,7 @@ func main() {
|
||||||
if *defaultsForCI {
|
if *defaultsForCI {
|
||||||
cfg.AppServiceAPI.DisableTLSValidation = true
|
cfg.AppServiceAPI.DisableTLSValidation = true
|
||||||
cfg.ClientAPI.RateLimiting.Enabled = false
|
cfg.ClientAPI.RateLimiting.Enabled = false
|
||||||
cfg.FederationAPI.DisableTLSValidation = true
|
cfg.FederationAPI.DisableTLSValidation = false
|
||||||
// don't hit matrix.org when running tests!!!
|
// don't hit matrix.org when running tests!!!
|
||||||
cfg.FederationAPI.KeyPerspectives = config.KeyPerspectives{}
|
cfg.FederationAPI.KeyPerspectives = config.KeyPerspectives{}
|
||||||
cfg.MSCs.MSCs = []string{"msc2836", "msc2946", "msc2444", "msc2753"}
|
cfg.MSCs.MSCs = []string{"msc2836", "msc2946", "msc2444", "msc2753"}
|
||||||
|
|
|
@ -32,9 +32,12 @@ Arguments:
|
||||||
`
|
`
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tlsCertFile = flag.String("tls-cert", "", "An X509 certificate file to generate for use for TLS")
|
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")
|
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")
|
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() {
|
func main() {
|
||||||
|
@ -54,8 +57,15 @@ func main() {
|
||||||
if *tlsCertFile == "" || *tlsKeyFile == "" {
|
if *tlsCertFile == "" || *tlsKeyFile == "" {
|
||||||
log.Fatal("Zero or both of --tls-key and --tls-cert must be supplied")
|
log.Fatal("Zero or both of --tls-key and --tls-cert must be supplied")
|
||||||
}
|
}
|
||||||
if err := test.NewTLSKey(*tlsKeyFile, *tlsCertFile); err != nil {
|
if *authorityCertFile == "" && *authorityKeyFile == "" {
|
||||||
panic(err)
|
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 cert file: %s\n", *tlsCertFile)
|
||||||
fmt.Printf("Created TLS key file: %s\n", *tlsKeyFile)
|
fmt.Printf("Created TLS key file: %s\n", *tlsKeyFile)
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
@ -158,11 +159,10 @@ func NewMatrixKey(matrixKeyPath string) (err error) {
|
||||||
|
|
||||||
const certificateDuration = time.Hour * 24 * 365 * 10
|
const certificateDuration = time.Hour * 24 * 365 * 10
|
||||||
|
|
||||||
// NewTLSKey generates a new RSA TLS key and certificate and writes it to a file.
|
func generateTLSTemplate(dnsNames []string) (*rsa.PrivateKey, *x509.Certificate, error) {
|
||||||
func NewTLSKey(tlsKeyPath, tlsCertPath string) error {
|
|
||||||
priv, err := rsa.GenerateKey(rand.Reader, 4096)
|
priv, err := rsa.GenerateKey(rand.Reader, 4096)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
notBefore := time.Now()
|
notBefore := time.Now()
|
||||||
|
@ -170,7 +170,7 @@ func NewTLSKey(tlsKeyPath, tlsCertPath string) error {
|
||||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
template := x509.Certificate{
|
template := x509.Certificate{
|
||||||
|
@ -180,20 +180,21 @@ func NewTLSKey(tlsKeyPath, tlsCertPath string) error {
|
||||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
BasicConstraintsValid: true,
|
BasicConstraintsValid: true,
|
||||||
|
DNSNames: dnsNames,
|
||||||
}
|
}
|
||||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
return priv, &template, nil
|
||||||
if err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
func writeCertificate(tlsCertPath string, derBytes []byte) error {
|
||||||
certOut, err := os.Create(tlsCertPath)
|
certOut, err := os.Create(tlsCertPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer certOut.Close() // nolint: errcheck
|
defer certOut.Close() // nolint: errcheck
|
||||||
if err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
|
return pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
func writePrivateKey(tlsKeyPath string, priv *rsa.PrivateKey) error {
|
||||||
keyOut, err := os.OpenFile(tlsKeyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
keyOut, err := os.OpenFile(tlsKeyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -205,3 +206,73 @@ func NewTLSKey(tlsKeyPath, tlsCertPath string) error {
|
||||||
})
|
})
|
||||||
return err
|
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)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue