2022-10-11 19:24:53 +00:00
|
|
|
// Package nebula contains helper functions and types which are useful for
|
|
|
|
// setting up nebula configs, processes, and deployments.
|
|
|
|
package nebula
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/slackhq/nebula/cert"
|
|
|
|
)
|
|
|
|
|
2022-11-05 14:23:29 +00:00
|
|
|
// HostPublicCredentials contains certificate and signing public keys which are
|
|
|
|
// able to be broadcast publicly.
|
|
|
|
type HostPublicCredentials struct {
|
2024-06-15 21:02:24 +00:00
|
|
|
Cert cert.NebulaCertificate
|
2024-06-10 20:31:29 +00:00
|
|
|
SigningKey SigningPublicKey
|
2022-11-05 14:23:29 +00:00
|
|
|
}
|
|
|
|
|
2024-06-10 20:31:29 +00:00
|
|
|
// HostPrivateCredentials contains the private key files which will
|
|
|
|
// need to be present on a particular host.
|
|
|
|
type HostPrivateCredentials struct {
|
2024-06-15 21:02:24 +00:00
|
|
|
EncryptingPrivateKey EncryptingPrivateKey
|
|
|
|
SigningPrivateKey SigningPrivateKey
|
2022-11-05 14:23:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// CAPublicCredentials contains certificate and signing public keys which are
|
|
|
|
// able to be broadcast publicly. The signing public key is the same one which
|
|
|
|
// is embedded into the certificate.
|
|
|
|
type CAPublicCredentials struct {
|
2024-06-15 21:02:24 +00:00
|
|
|
Cert cert.NebulaCertificate
|
2024-06-10 20:31:29 +00:00
|
|
|
SigningKey SigningPublicKey
|
2022-10-11 19:24:53 +00:00
|
|
|
}
|
|
|
|
|
2022-10-29 19:11:40 +00:00
|
|
|
// CACredentials contains the certificate and private files which can be used to
|
|
|
|
// create and validate HostCredentials. Each file is PEM encoded.
|
|
|
|
type CACredentials struct {
|
2024-06-10 20:31:29 +00:00
|
|
|
Public CAPublicCredentials
|
|
|
|
SigningPrivateKey SigningPrivateKey
|
2022-10-15 11:14:38 +00:00
|
|
|
}
|
|
|
|
|
2024-06-15 21:02:24 +00:00
|
|
|
// NewHostCert generates and signs a new host certificate containing the given
|
|
|
|
// public key.
|
|
|
|
func NewHostCert(
|
|
|
|
caCreds CACredentials,
|
|
|
|
hostPub EncryptingPublicKey,
|
|
|
|
hostName string,
|
|
|
|
ip net.IP,
|
2022-10-11 19:24:53 +00:00
|
|
|
) (
|
2024-06-15 21:02:24 +00:00
|
|
|
cert.NebulaCertificate, error,
|
2022-10-11 19:24:53 +00:00
|
|
|
) {
|
2024-06-15 21:02:24 +00:00
|
|
|
caCert := caCreds.Public.Cert
|
2022-10-11 19:24:53 +00:00
|
|
|
|
2022-10-29 19:11:40 +00:00
|
|
|
issuer, err := caCert.Sha256Sum()
|
2022-10-11 19:24:53 +00:00
|
|
|
if err != nil {
|
2024-06-15 21:02:24 +00:00
|
|
|
return cert.NebulaCertificate{}, fmt.Errorf("getting ca.crt issuer: %w", err)
|
2022-10-11 19:24:53 +00:00
|
|
|
}
|
|
|
|
|
2022-10-29 19:11:40 +00:00
|
|
|
expireAt := caCert.Details.NotAfter.Add(-1 * time.Second)
|
2022-10-11 19:24:53 +00:00
|
|
|
|
2022-10-29 19:11:40 +00:00
|
|
|
subnet := caCert.Details.Subnets[0]
|
2022-10-16 20:17:26 +00:00
|
|
|
if !subnet.Contains(ip) {
|
2024-06-15 21:02:24 +00:00
|
|
|
return cert.NebulaCertificate{}, fmt.Errorf("invalid ip %q, not contained by network subnet %q", ip, subnet)
|
2022-10-11 19:24:53 +00:00
|
|
|
}
|
|
|
|
|
2022-10-29 19:11:40 +00:00
|
|
|
hostCert := cert.NebulaCertificate{
|
2022-10-11 19:24:53 +00:00
|
|
|
Details: cert.NebulaCertificateDetails{
|
2022-10-16 20:17:26 +00:00
|
|
|
Name: hostName,
|
|
|
|
Ips: []*net.IPNet{{
|
|
|
|
IP: ip,
|
|
|
|
Mask: subnet.Mask,
|
|
|
|
}},
|
2022-10-11 19:24:53 +00:00
|
|
|
NotBefore: time.Now(),
|
|
|
|
NotAfter: expireAt,
|
2024-06-15 21:02:24 +00:00
|
|
|
PublicKey: hostPub.Bytes(),
|
2022-10-11 19:24:53 +00:00
|
|
|
IsCA: false,
|
|
|
|
Issuer: issuer,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2024-06-15 21:02:24 +00:00
|
|
|
if err := hostCert.CheckRootConstrains(&caCert); err != nil {
|
|
|
|
return cert.NebulaCertificate{}, fmt.Errorf("validating certificate constraints: %w", err)
|
2022-10-11 19:24:53 +00:00
|
|
|
}
|
|
|
|
|
2024-06-10 20:31:29 +00:00
|
|
|
if err := signCert(&hostCert, caCreds.SigningPrivateKey); err != nil {
|
2024-06-15 21:02:24 +00:00
|
|
|
return cert.NebulaCertificate{}, fmt.Errorf("signing host cert with ca.key: %w", err)
|
2023-08-27 14:09:03 +00:00
|
|
|
}
|
|
|
|
|
2024-06-15 21:02:24 +00:00
|
|
|
return hostCert, nil
|
2023-08-27 14:09:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewHostCredentials generates a new key/cert for a nebula host using the CA
|
|
|
|
// key which will be found in the adminFS.
|
|
|
|
func NewHostCredentials(
|
|
|
|
caCreds CACredentials, hostName string, ip net.IP,
|
|
|
|
) (
|
2024-06-10 20:31:29 +00:00
|
|
|
pub HostPublicCredentials, priv HostPrivateCredentials, err error,
|
2023-08-27 14:09:03 +00:00
|
|
|
) {
|
|
|
|
|
2024-06-15 21:02:24 +00:00
|
|
|
var (
|
|
|
|
encPrivKey = NewEncryptingPrivateKey()
|
|
|
|
encPubKey = encPrivKey.PublicKey()
|
2024-06-10 20:31:29 +00:00
|
|
|
|
2024-06-15 21:02:24 +00:00
|
|
|
signingPubKey, signingPrivKey = GenerateSigningPair()
|
|
|
|
)
|
2022-10-11 19:24:53 +00:00
|
|
|
|
2024-06-15 21:02:24 +00:00
|
|
|
hostCert, err := NewHostCert(caCreds, encPubKey, hostName, ip)
|
2022-10-11 19:24:53 +00:00
|
|
|
if err != nil {
|
2024-06-10 20:31:29 +00:00
|
|
|
err = fmt.Errorf("creating host certificate: %w", err)
|
|
|
|
return
|
2022-10-11 19:24:53 +00:00
|
|
|
}
|
|
|
|
|
2024-06-10 20:31:29 +00:00
|
|
|
pub = HostPublicCredentials{
|
2024-06-15 21:02:24 +00:00
|
|
|
Cert: hostCert,
|
2024-06-10 20:31:29 +00:00
|
|
|
SigningKey: signingPubKey,
|
|
|
|
}
|
|
|
|
|
|
|
|
priv = HostPrivateCredentials{
|
2024-06-15 21:02:24 +00:00
|
|
|
EncryptingPrivateKey: encPrivKey,
|
|
|
|
SigningPrivateKey: signingPrivKey,
|
2024-06-10 20:31:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return
|
2022-10-11 19:24:53 +00:00
|
|
|
}
|
2022-10-15 11:14:38 +00:00
|
|
|
|
2022-10-29 19:11:40 +00:00
|
|
|
// NewCACredentials generates a CACredentials. The domain should be the network's root domain,
|
2022-10-15 11:14:38 +00:00
|
|
|
// and is included in the signing certificate's Name field.
|
2022-10-29 19:11:40 +00:00
|
|
|
func NewCACredentials(domain string, subnet *net.IPNet) (CACredentials, error) {
|
2024-06-15 21:02:24 +00:00
|
|
|
var (
|
|
|
|
signingPubKey, signingPrivKey = GenerateSigningPair()
|
|
|
|
now = time.Now()
|
|
|
|
expireAt = now.Add(2 * 365 * 24 * time.Hour)
|
|
|
|
)
|
2022-10-15 11:14:38 +00:00
|
|
|
|
2022-10-29 19:11:40 +00:00
|
|
|
caCert := cert.NebulaCertificate{
|
2022-10-15 11:14:38 +00:00
|
|
|
Details: cert.NebulaCertificateDetails{
|
2023-08-05 21:53:17 +00:00
|
|
|
Name: fmt.Sprintf("%s isle root cert", domain),
|
2022-10-16 20:17:26 +00:00
|
|
|
Subnets: []*net.IPNet{subnet},
|
2022-10-15 11:14:38 +00:00
|
|
|
NotBefore: now,
|
|
|
|
NotAfter: expireAt,
|
2022-11-05 14:23:29 +00:00
|
|
|
PublicKey: signingPubKey,
|
2022-10-15 11:14:38 +00:00
|
|
|
IsCA: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2024-06-10 20:31:29 +00:00
|
|
|
if err := signCert(&caCert, signingPrivKey); err != nil {
|
2022-10-29 19:11:40 +00:00
|
|
|
return CACredentials{}, fmt.Errorf("signing caCert: %w", err)
|
2022-10-15 11:14:38 +00:00
|
|
|
}
|
|
|
|
|
2022-10-29 19:11:40 +00:00
|
|
|
return CACredentials{
|
2022-11-05 14:23:29 +00:00
|
|
|
Public: CAPublicCredentials{
|
2024-06-15 21:02:24 +00:00
|
|
|
Cert: caCert,
|
2024-06-10 20:31:29 +00:00
|
|
|
SigningKey: signingPubKey,
|
2022-11-05 14:23:29 +00:00
|
|
|
},
|
2024-06-10 20:31:29 +00:00
|
|
|
SigningPrivateKey: signingPrivKey,
|
2022-10-15 11:14:38 +00:00
|
|
|
}, nil
|
|
|
|
}
|