Serge Bazanski | 02e1598 | 2021-03-17 22:39:00 +0000 | [diff] [blame] | 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "encoding/pem" |
| 6 | "fmt" |
| 7 | "time" |
| 8 | |
| 9 | "github.com/cloudflare/cfssl/config" |
| 10 | "github.com/cloudflare/cfssl/csr" |
| 11 | "github.com/cloudflare/cfssl/helpers" |
| 12 | "github.com/cloudflare/cfssl/signer" |
| 13 | "github.com/cloudflare/cfssl/signer/local" |
| 14 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| 15 | |
| 16 | pb "code.hackerspace.pl/hscloud/cluster/prodvider/proto" |
| 17 | ) |
| 18 | |
| 19 | // crdbSigner returns a cfssl signer (CA) for a crdb cluster, by loading the CA |
| 20 | // cert/key from Kubernetes. |
| 21 | func (p *prodvider) crdbSigner(ctx context.Context, cluster string) (*local.Signer, error) { |
| 22 | policy := &config.Signing{ |
| 23 | Profiles: map[string]*config.SigningProfile{ |
| 24 | "client": &config.SigningProfile{ |
| 25 | Usage: []string{"signing", "key encipherment"}, |
| 26 | ExpiryString: "30d", |
| 27 | }, |
| 28 | }, |
| 29 | Default: config.DefaultConfig(), |
| 30 | } |
| 31 | |
| 32 | namespace := fmt.Sprintf("crdb-%s", cluster) |
| 33 | |
| 34 | secret, err := p.k8s.CoreV1().Secrets(namespace).Get(ctx, "cluster-ca", metav1.GetOptions{}) |
| 35 | if err != nil { |
| 36 | return nil, fmt.Errorf("hspki secret get failed: %w", err) |
| 37 | } |
| 38 | |
| 39 | parsedCa, err := helpers.ParseCertificatePEM(secret.Data["tls.crt"]) |
| 40 | if err != nil { |
| 41 | return nil, fmt.Errorf("when parsing tls.crt: %w", err) |
| 42 | } |
| 43 | |
| 44 | priv, err := helpers.ParsePrivateKeyPEMWithPassword(secret.Data["tls.key"], nil) |
| 45 | if err != nil { |
| 46 | return nil, fmt.Errorf("when parsing tls.key: %w", err) |
| 47 | } |
| 48 | |
| 49 | return local.NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy) |
| 50 | } |
| 51 | |
| 52 | // crdbCreds returns a crdb certificate/key for an SSO useron a given cluster. |
| 53 | // The returned certificate is valid for connecting to crdb. |
| 54 | func (p *prodvider) crdbCreds(ctx context.Context, username, cluster string) (*pb.CockroachDBKeys_Cluster, error) { |
| 55 | username = fmt.Sprintf("dev-%s", username) |
| 56 | |
| 57 | s, err := p.crdbSigner(ctx, cluster) |
| 58 | if err != nil { |
| 59 | return nil, fmt.Errorf("hspkiSigner: %w", err) |
| 60 | } |
| 61 | |
| 62 | signerCert, _ := s.Certificate("", "") |
| 63 | req := &csr.CertificateRequest{ |
| 64 | CN: username, |
Serge Bazanski | 97b5cd7 | 2023-07-28 17:14:50 +0000 | [diff] [blame] | 65 | KeyRequest: &csr.KeyRequest{ |
Serge Bazanski | 02e1598 | 2021-03-17 22:39:00 +0000 | [diff] [blame] | 66 | A: "rsa", |
| 67 | S: 4096, |
| 68 | }, |
| 69 | Names: []csr.Name{ |
| 70 | { |
| 71 | O: "prodvider", |
| 72 | }, |
| 73 | }, |
| 74 | Hosts: []string{username}, |
| 75 | } |
| 76 | |
| 77 | g := &csr.Generator{ |
| 78 | Validator: func(req *csr.CertificateRequest) error { return nil }, |
| 79 | } |
| 80 | |
| 81 | csrPEM, keyPEM, err := g.ProcessRequest(req) |
| 82 | if err != nil { |
| 83 | return nil, fmt.Errorf("when making CSR: %w", err) |
| 84 | } |
| 85 | |
| 86 | signReq := signer.SignRequest{ |
| 87 | Hosts: []string{username}, |
| 88 | Request: string(csrPEM), |
| 89 | Profile: "client", |
| 90 | NotAfter: time.Now().Add(9 * time.Hour), |
| 91 | } |
| 92 | |
| 93 | certPEM, err := s.Sign(signReq) |
| 94 | if err != nil { |
| 95 | return nil, fmt.Errorf("when issuing certificate: %w", err) |
| 96 | } |
| 97 | |
| 98 | caPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: signerCert.Raw}) |
| 99 | |
| 100 | return &pb.CockroachDBKeys_Cluster{ |
| 101 | Name: cluster, |
| 102 | Ca: caPEM, |
| 103 | Cert: certPEM, |
| 104 | Key: keyPEM, |
| 105 | Username: username, |
| 106 | }, nil |
| 107 | } |