forked from hswaw/hscloud
108 lines
2.7 KiB
Go
108 lines
2.7 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"encoding/pem"
|
||
|
"fmt"
|
||
|
"time"
|
||
|
|
||
|
"github.com/cloudflare/cfssl/config"
|
||
|
"github.com/cloudflare/cfssl/csr"
|
||
|
"github.com/cloudflare/cfssl/helpers"
|
||
|
"github.com/cloudflare/cfssl/signer"
|
||
|
"github.com/cloudflare/cfssl/signer/local"
|
||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||
|
|
||
|
pb "code.hackerspace.pl/hscloud/cluster/prodvider/proto"
|
||
|
)
|
||
|
|
||
|
// crdbSigner returns a cfssl signer (CA) for a crdb cluster, by loading the CA
|
||
|
// cert/key from Kubernetes.
|
||
|
func (p *prodvider) crdbSigner(ctx context.Context, cluster string) (*local.Signer, error) {
|
||
|
policy := &config.Signing{
|
||
|
Profiles: map[string]*config.SigningProfile{
|
||
|
"client": &config.SigningProfile{
|
||
|
Usage: []string{"signing", "key encipherment"},
|
||
|
ExpiryString: "30d",
|
||
|
},
|
||
|
},
|
||
|
Default: config.DefaultConfig(),
|
||
|
}
|
||
|
|
||
|
namespace := fmt.Sprintf("crdb-%s", cluster)
|
||
|
|
||
|
secret, err := p.k8s.CoreV1().Secrets(namespace).Get(ctx, "cluster-ca", metav1.GetOptions{})
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("hspki secret get failed: %w", err)
|
||
|
}
|
||
|
|
||
|
parsedCa, err := helpers.ParseCertificatePEM(secret.Data["tls.crt"])
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("when parsing tls.crt: %w", err)
|
||
|
}
|
||
|
|
||
|
priv, err := helpers.ParsePrivateKeyPEMWithPassword(secret.Data["tls.key"], nil)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("when parsing tls.key: %w", err)
|
||
|
}
|
||
|
|
||
|
return local.NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy)
|
||
|
}
|
||
|
|
||
|
// crdbCreds returns a crdb certificate/key for an SSO useron a given cluster.
|
||
|
// The returned certificate is valid for connecting to crdb.
|
||
|
func (p *prodvider) crdbCreds(ctx context.Context, username, cluster string) (*pb.CockroachDBKeys_Cluster, error) {
|
||
|
username = fmt.Sprintf("dev-%s", username)
|
||
|
|
||
|
s, err := p.crdbSigner(ctx, cluster)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("hspkiSigner: %w", err)
|
||
|
}
|
||
|
|
||
|
signerCert, _ := s.Certificate("", "")
|
||
|
req := &csr.CertificateRequest{
|
||
|
CN: username,
|
||
|
KeyRequest: &csr.BasicKeyRequest{
|
||
|
A: "rsa",
|
||
|
S: 4096,
|
||
|
},
|
||
|
Names: []csr.Name{
|
||
|
{
|
||
|
O: "prodvider",
|
||
|
},
|
||
|
},
|
||
|
Hosts: []string{username},
|
||
|
}
|
||
|
|
||
|
g := &csr.Generator{
|
||
|
Validator: func(req *csr.CertificateRequest) error { return nil },
|
||
|
}
|
||
|
|
||
|
csrPEM, keyPEM, err := g.ProcessRequest(req)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("when making CSR: %w", err)
|
||
|
}
|
||
|
|
||
|
signReq := signer.SignRequest{
|
||
|
Hosts: []string{username},
|
||
|
Request: string(csrPEM),
|
||
|
Profile: "client",
|
||
|
NotAfter: time.Now().Add(9 * time.Hour),
|
||
|
}
|
||
|
|
||
|
certPEM, err := s.Sign(signReq)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("when issuing certificate: %w", err)
|
||
|
}
|
||
|
|
||
|
caPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: signerCert.Raw})
|
||
|
|
||
|
return &pb.CockroachDBKeys_Cluster{
|
||
|
Name: cluster,
|
||
|
Ca: caPEM,
|
||
|
Cert: certPEM,
|
||
|
Key: keyPEM,
|
||
|
Username: username,
|
||
|
}, nil
|
||
|
}
|