blob: e747889cea3ba48c5f917ba5e954ade01f1e1c16 [file] [log] [blame]
Serge Bazanskif3312ef2020-08-01 17:15:52 +02001package main
2
3import (
4 "encoding/pem"
5 "fmt"
6 "time"
7
8 "github.com/cloudflare/cfssl/config"
9 "github.com/cloudflare/cfssl/csr"
10 "github.com/cloudflare/cfssl/helpers"
11 "github.com/cloudflare/cfssl/signer"
12 "github.com/cloudflare/cfssl/signer/local"
13 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14
15 pb "code.hackerspace.pl/hscloud/cluster/prodvider/proto"
16)
17
Serge Bazanski4ded56a2020-08-01 22:01:05 +020018// hspkiSigner returns a cfssl signer (CA) for HSPKI, by loading the CA
19// cert/key from Kubernetes.
Serge Bazanskif3312ef2020-08-01 17:15:52 +020020func (p *prodvider) hspkiSigner() (*local.Signer, error) {
21 policy := &config.Signing{
22 Profiles: map[string]*config.SigningProfile{
Serge Bazanski4ded56a2020-08-01 22:01:05 +020023 "client-server": &config.SigningProfile{
24 Usage: []string{"signing", "key encipherment", "server auth", "client auth"},
Serge Bazanskif3312ef2020-08-01 17:15:52 +020025 ExpiryString: "30d",
26 },
27 },
28 Default: config.DefaultConfig(),
29 }
30
31 secret, err := p.k8s.CoreV1().Secrets("cert-manager").Get("pki-selfsigned-cert", metav1.GetOptions{})
32 if err != nil {
33 return nil, fmt.Errorf("hspki secret get failed: %w", err)
34 }
35
36 parsedCa, err := helpers.ParseCertificatePEM(secret.Data["tls.crt"])
37 if err != nil {
38 return nil, fmt.Errorf("when parsing tls.crt: %w", err)
39 }
40
41 priv, err := helpers.ParsePrivateKeyPEMWithPassword(secret.Data["tls.key"], nil)
42 if err != nil {
43 return nil, fmt.Errorf("when parsing tls.key: %w", err)
44 }
45
46 return local.NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy)
47}
48
Serge Bazanski4ded56a2020-08-01 22:01:05 +020049// hspkiCreds returns a HSPKI certificate/key for an SSO user. The returned
50// certificate is valida for both server and client usage.
Serge Bazanskif3312ef2020-08-01 17:15:52 +020051func (p *prodvider) hspkiCreds(username string) (*pb.HSPKIKeys, error) {
52 principal := fmt.Sprintf("%s.sso.hswaw.net", username)
53
54 s, err := p.hspkiSigner()
55 if err != nil {
56 return nil, fmt.Errorf("hspkiSigner: %w", err)
57 }
58
59 signerCert, _ := s.Certificate("", "")
60 req := &csr.CertificateRequest{
61 CN: principal,
62 KeyRequest: &csr.BasicKeyRequest{
63 A: "rsa",
64 S: 4096,
65 },
66 Names: []csr.Name{
67 {
68 O: "prodvider",
69 OU: fmt.Sprintf("Prodvider HSPKI Cert for %s", username),
70 },
71 },
72 }
73
74 g := &csr.Generator{
75 Validator: func(req *csr.CertificateRequest) error { return nil },
76 }
77
78 csrPEM, keyPEM, err := g.ProcessRequest(req)
79 if err != nil {
80 return nil, fmt.Errorf("when making CSR: %w", err)
81 }
82
83 signReq := signer.SignRequest{
84 Hosts: []string{},
85 Request: string(csrPEM),
Serge Bazanski4ded56a2020-08-01 22:01:05 +020086 Profile: "client-server",
Serge Bazanskif3312ef2020-08-01 17:15:52 +020087 NotAfter: time.Now().Add(9 * time.Hour),
88 }
89
90 certPEM, err := s.Sign(signReq)
91 if err != nil {
92 return nil, fmt.Errorf("when issuing certificate: %w", err)
93 }
94
95 caPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: signerCert.Raw})
96
97 return &pb.HSPKIKeys{
98 Ca: caPEM,
99 Cert: certPEM,
100 Key: keyPEM,
101 Principal: principal,
102 }, nil
103}