blob: 348754c8155090571ecf87d8a8b347f1ed119412 [file] [log] [blame]
Serge Bazanski02e15982021-03-17 22:39:00 +00001package main
2
3import (
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.
21func (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.
54func (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,
65 KeyRequest: &csr.BasicKeyRequest{
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}