forked from hswaw/hscloud
Sergiusz Bazanski
b13b7ffcdb
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
149 lines
4.1 KiB
Go
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)
|
|
}
|
|
}
|