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" ) // hspkiSigner returns a cfssl signer (CA) for HSPKI, by loading the CA // cert/key from Kubernetes. func (p *prodvider) hspkiSigner(ctx context.Context) (*local.Signer, error) { policy := &config.Signing{ Profiles: map[string]*config.SigningProfile{ "client-server": &config.SigningProfile{ Usage: []string{"signing", "key encipherment", "server auth", "client auth"}, ExpiryString: "30d", }, }, Default: config.DefaultConfig(), } secret, err := p.k8s.CoreV1().Secrets("cert-manager").Get(ctx, "pki-selfsigned-cert", 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) } // hspkiCreds returns a HSPKI certificate/key for an SSO user. The returned // certificate is valida for both server and client usage. func (p *prodvider) hspkiCreds(ctx context.Context, username string) (*pb.HSPKIKeys, error) { principal := fmt.Sprintf("%s.sso.hswaw.net", username) s, err := p.hspkiSigner(ctx) if err != nil { return nil, fmt.Errorf("hspkiSigner: %w", err) } signerCert, _ := s.Certificate("", "") req := &csr.CertificateRequest{ CN: principal, KeyRequest: &csr.KeyRequest{ A: "rsa", S: 4096, }, Names: []csr.Name{ { O: "prodvider", OU: fmt.Sprintf("Prodvider HSPKI Cert for %s", 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{}, Request: string(csrPEM), Profile: "client-server", 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.HSPKIKeys{ Ca: caPEM, Cert: certPEM, Key: keyPEM, Principal: principal, }, nil }