Seán C. McCord 4aaa7f6587 fix(init): fix leaky ticker (#784)
Ticker in cert generation poll loop was never stopped.

Signed-off-by: Seán C McCord <ulexus@gmail.com>
2019-06-26 10:19:18 -07:00

103 lines
2.7 KiB
Go

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package gen
import (
"context"
"fmt"
"log"
"time"
"github.com/talos-systems/talos/internal/app/trustd/proto"
"github.com/talos-systems/talos/internal/pkg/grpc/middleware/auth/basic"
"github.com/talos-systems/talos/pkg/crypto/x509"
"github.com/talos-systems/talos/pkg/userdata"
"google.golang.org/grpc"
)
// Generator represents the OS identity generator.
type Generator struct {
client proto.TrustdClient
}
// NewGenerator initializes a Generator with a preconfigured grpc.ClientConn.
func NewGenerator(data *userdata.UserData, port int) (g *Generator, err error) {
if len(data.Services.Trustd.Endpoints) == 0 {
return nil, fmt.Errorf("at least one root of trust endpoint is required")
}
creds, err := basic.NewCredentials(data.Services.Trustd)
if err != nil {
return nil, err
}
// TODO: In the case of failure, attempt to generate the identity from
// another RoT.
var conn *grpc.ClientConn
conn, err = basic.NewConnection(data.Services.Trustd.Endpoints[0], port, creds)
if err != nil {
return nil, err
}
client := proto.NewTrustdClient(conn)
return &Generator{
client: client,
}, nil
}
// Certificate implements the proto.TrustdClient interface.
func (g *Generator) Certificate(in *proto.CertificateRequest) (resp *proto.CertificateResponse, err error) {
ctx := context.Background()
resp, err = g.client.Certificate(ctx, in)
if err != nil {
return
}
return resp, err
}
// Identity creates a CSR and sends it to trustd for signing.
// A signed certificate is returned.
func (g *Generator) Identity(data *userdata.UserData) (err error) {
if data.Security == nil {
data.Security = &userdata.Security{}
}
data.Security.OS = &userdata.OSSecurity{CA: &x509.PEMEncodedCertificateAndKey{}}
var csr *x509.CertificateSigningRequest
if csr, err = data.NewIdentityCSR(); err != nil {
return err
}
req := &proto.CertificateRequest{
Csr: csr.X509CertificateRequestPEM,
}
return poll(g, req, data.Security.OS)
}
func poll(g *Generator, in *proto.CertificateRequest, data *userdata.OSSecurity) (err error) {
timeout := time.NewTimer(time.Minute * 5)
defer timeout.Stop()
tick := time.NewTicker(time.Second * 5)
defer tick.Stop()
for {
select {
case <-timeout.C:
return fmt.Errorf("timeout waiting for certificate")
case <-tick.C:
resp, _err := g.Certificate(in)
if _err != nil {
log.Println(_err)
continue
}
data.CA = &x509.PEMEncodedCertificateAndKey{}
data.CA.Crt = resp.Ca
data.Identity.Crt = resp.Crt
return nil
}
}
}