cloud-provider-pve/pkg/approver/approver.go
2020-10-31 16:53:35 +01:00

160 lines
4.1 KiB
Go

package approver
import (
"context"
"errors"
"net"
"strings"
pve "git.giftfish.de/ston1th/pve-go"
//"k8s.io/client-go/kubernetes/typed/certificates/v1"
"github.com/go-logr/logr"
certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
"k8s.io/kubernetes/pkg/apis/certificates"
)
var ErrNoKubeletServingCSR = errors.New("CSR is no kubelet serving certificate")
func checkCSR(ctx context.Context, pveClient *pve.Client, request *certificatesv1beta1.CertificateSigningRequest) error {
req, err := certificates.ParseCSR(request.Spec.Request)
if err != nil {
return err
}
usages := make([]string, len(request.Spec.Usages))
for i, v := range request.Spec.Usages {
usages[i] = string(v)
}
if !certificates.IsKubeletServingCSR(req, sets.NewString(usages...)) {
return ErrNoKubeletServingCSR
}
hostname := strings.TrimPrefix(req.Subject.CommonName, "system:node:")
ref, err := pveClient.Pool.FindServerByName(ctx, "", hostname)
if err != nil {
return err
}
if ref.Name != hostname {
return errors.New("CSR hostname and PVE server name do not match")
}
ok := false
for _, dns := range req.DNSNames {
if dns == hostname {
ok = true
}
}
if len(req.DNSNames) == 0 {
ok = true
}
if !ok {
return errors.New("req.DNSNames does not contain hostname")
}
srv, err := pveClient.Server.GetByRef(ctx, ref)
if err != nil {
return err
}
ok = false
for _, ip := range req.IPAddresses {
for _, ipc := range srv.IPConfig {
ipv4, _, err := net.ParseCIDR(ipc.IPv4CIDR)
if err == nil {
if ip.String() == ipv4.String() {
ok = true
break
}
}
ipv6, _, err := net.ParseCIDR(ipc.IPv6CIDR)
if err == nil {
if ip.String() == ipv6.String() {
ok = true
break
}
}
}
if ok {
break
}
}
if len(req.IPAddresses) == 0 {
ok = true
}
if !ok {
return errors.New("req.IPAddresses does not contain a valid IP")
}
return nil
}
var conditionv1beta1 = certificatesv1beta1.CertificateSigningRequestCondition{
Type: certificatesv1beta1.CertificateApproved,
Reason: "AutoApproved",
Message: "Auto approving kubelet client certificate in PVE Cluster",
}
func ApproveV1beta1(log logr.Logger, pveClient *pve.Client, client v1beta1.CertificateSigningRequestInterface, request *certificatesv1beta1.CertificateSigningRequest) error {
if len(request.Status.Conditions) > 0 {
return nil
}
ctx := context.Background()
err := checkCSR(ctx, pveClient, request)
if err == ErrNoKubeletServingCSR {
return nil
}
if err != nil {
return err
}
for {
if len(request.Status.Conditions) > 0 {
return nil
}
request.Status.Conditions = append(request.Status.Conditions, conditionv1beta1)
// Submit the updated CSR.
if _, err := client.UpdateApproval(ctx, request, metav1.UpdateOptions{}); err != nil {
if strings.Contains(err.Error(), "the object has been modified") {
// The CSR might have been updated by a third-party, retry until we
// succeed.
request, err = client.Get(ctx, request.ObjectMeta.Name, metav1.GetOptions{})
if err != nil {
return err
}
continue
}
return err
}
log.Info("csr approval successful", "name", request.ObjectMeta.Name)
return nil
}
}
//func ApproveV1(pveClient *pve.Client, client v1.CertificateSigningRequestInterface, request *certificates.CertificateSigningRequest) error {
// if len(request.Status.Conditions) > 0 {
// return nil
// }
// err := checkCSR(pveClient, request)
// if err != nil {
// return err
// }
//
// for {
// if len(request.Status.Conditions) > 0 {
// return nil
// }
// request.Status.Conditions = append(request.Status.Conditions, condition)
// // Submit the updated CSR.
// if _, err := client.UpdateApproval(request); err != nil {
// if strings.Contains(err.Error(), "the object has been modified") {
// // The CSR might have been updated by a third-party, retry until we
// // succeed.
// request, err = client.Get(request.ObjectMeta.Name)
// if err != nil {
// return err
// }
// continue
// }
// return err
// }
// return nil
// }
//}