hscloud/cluster/prodvider/main.go
Sergiusz Bazanski b13b7ffcdb prod{access,vider}: implement
Prodaccess/Prodvider allow issuing short-lived certificates for all SSO
users to access the kubernetes cluster.

Currently, all users get a personal-$username namespace in which they
have adminitrative rights. Otherwise, they get no access.

In addition, we define a static CRB to allow some admins access to
everything. In the future, this will be more granular.

We also update relevant documentation.

Change-Id: Ia18594eea8a9e5efbb3e9a25a04a28bbd6a42153
2019-08-30 23:08:18 +02:00

149 lines
4.1 KiB
Go

package main
import (
"flag"
"io/ioutil"
"math/rand"
"net"
"os"
"time"
"github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/signer/local"
"github.com/golang/glog"
"google.golang.org/grpc"
"k8s.io/client-go/kubernetes"
pb "code.hackerspace.pl/hscloud/cluster/prodvider/proto"
)
var (
flagLDAPServer string
flagLDAPBindDN string
flagLDAPGroupSearchBase string
flagListenAddress string
flagKubernetesHost string
flagCACertificatePath string
flagCAKeyPath string
flagKubeCACertificatePath string
flagProdviderCN string
)
func init() {
flag.Set("logtostderr", "true")
}
type prodvider struct {
sign *local.Signer
k8s *kubernetes.Clientset
srv *grpc.Server
kubeCAPEM []byte
}
func newProdvider() *prodvider {
policy := &config.Signing{
Profiles: map[string]*config.SigningProfile{
"server": &config.SigningProfile{
Usage: []string{"signing", "key encipherment", "server auth"},
ExpiryString: "30d",
},
"client": &config.SigningProfile{
Usage: []string{"signing", "key encipherment", "client auth"},
ExpiryString: "30d",
},
"client-server": &config.SigningProfile{
Usage: []string{"signing", "key encipherment", "server auth", "client auth"},
ExpiryString: "30d",
},
},
Default: config.DefaultConfig(),
}
sign, err := local.NewSignerFromFile(flagCACertificatePath, flagCAKeyPath, policy)
if err != nil {
glog.Exitf("Could not create signer: %v", err)
}
kubeCAPEM, err := ioutil.ReadFile(flagKubeCACertificatePath)
if err != nil {
glog.Exitf("Could not read kube CA cert path: %v")
}
return &prodvider{
sign: sign,
kubeCAPEM: kubeCAPEM,
}
}
// Timebomb restarts the prodvider after a deadline, usually 7 days +/- 4 days.
// This is to ensure we serve with up-to-date certificates and that the service
// can still come up after restart.
func timebomb(srv *grpc.Server) {
deadline := time.Now()
deadline = deadline.Add(3 * 24 * time.Hour)
rand.Seed(time.Now().UnixNano())
jitter := rand.Intn(8 * 24 * 60 * 60)
deadline = deadline.Add(time.Duration(jitter) * time.Second)
glog.Infof("Timebomb deadline set to %v", deadline)
t := time.NewTicker(time.Minute)
for {
<-t.C
if time.Now().After(deadline) {
break
}
}
// Start killing connections, and wait one minute...
go srv.GracefulStop()
<-t.C
glog.Infof("Timebomb deadline exceeded, restarting.")
os.Exit(0)
}
func main() {
flag.StringVar(&flagLDAPServer, "ldap_server", "ldap.hackerspace.pl:636", "Address of LDAP server")
flag.StringVar(&flagLDAPBindDN, "ldap_bind_dn", "uid=%s,ou=People,dc=hackerspace,dc=pl", "LDAP Bind DN")
flag.StringVar(&flagLDAPGroupSearchBase, "ldap_group_search_base_dn", "ou=Group,dc=hackerspace,dc=pl", "LDAP Group Search Base DN")
flag.StringVar(&flagListenAddress, "listen_address", "127.0.0.1:8080", "gRPC listen address")
flag.StringVar(&flagKubernetesHost, "kubernetes_host", "k0.hswaw.net:4001", "Kubernetes API host")
flag.StringVar(&flagCACertificatePath, "ca_certificate_path", "", "CA certificate path (for signer)")
flag.StringVar(&flagCAKeyPath, "ca_key_path", "", "CA key path (for signer)")
flag.StringVar(&flagKubeCACertificatePath, "kube_ca_certificate_path", "", "CA certificate path (for checking kube apiserver)")
flag.StringVar(&flagProdviderCN, "prodvider_cn", "prodvider.hswaw.net", "CN of certificate that prodvider will use")
flag.Parse()
if flagCACertificatePath == "" || flagCAKeyPath == "" {
glog.Exitf("CA certificate and key must be provided")
}
p := newProdvider()
err := p.kubernetesConnect()
if err != nil {
glog.Exitf("Could not connect to kubernetes: %v", err)
}
creds := p.selfCreds()
// Start serving gRPC
grpcLis, err := net.Listen("tcp", flagListenAddress)
if err != nil {
glog.Exitf("Could not listen for gRPC on %q: %v", flagListenAddress, err)
}
glog.Infof("Starting gRPC on %q...", flagListenAddress)
grpcSrv := grpc.NewServer(creds)
pb.RegisterProdviderServer(grpcSrv, p)
go timebomb(grpcSrv)
err = grpcSrv.Serve(grpcLis)
if err != nil {
glog.Exitf("Could not serve gRPC: %v", err)
}
}