-
Notifications
You must be signed in to change notification settings - Fork 743
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Introducing a Validating Admission Controller (#1021)
* feat: Introducing a Validating Admission Controller Signed-off-by: Derek Wang <[email protected]>
- Loading branch information
Showing
44 changed files
with
1,859 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package tls | ||
|
||
import ( | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"crypto/x509" | ||
"crypto/x509/pkix" | ||
"encoding/pem" | ||
"math/big" | ||
"time" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
func certTemplate(org string, hosts []string, notAfter time.Time) (*x509.Certificate, error) { | ||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) | ||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to generate serial number") | ||
} | ||
return &x509.Certificate{ | ||
SerialNumber: serialNumber, | ||
Subject: pkix.Name{ | ||
Organization: []string{org}, | ||
}, | ||
SignatureAlgorithm: x509.SHA256WithRSA, | ||
NotBefore: time.Now(), | ||
NotAfter: notAfter, | ||
BasicConstraintsValid: true, | ||
DNSNames: hosts, | ||
}, nil | ||
} | ||
|
||
func createCACertTemplate(org string, hosts []string, notAfter time.Time) (*x509.Certificate, error) { | ||
rootCert, err := certTemplate(org, hosts, notAfter) | ||
if err != nil { | ||
return nil, err | ||
} | ||
rootCert.IsCA = true | ||
rootCert.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature | ||
rootCert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth} | ||
return rootCert, nil | ||
} | ||
|
||
func createServerCertTemplate(org string, hosts []string, notAfter time.Time) (*x509.Certificate, error) { | ||
serverCert, err := certTemplate(org, hosts, notAfter) | ||
if err != nil { | ||
return nil, err | ||
} | ||
serverCert.KeyUsage = x509.KeyUsageDigitalSignature | ||
serverCert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} | ||
return serverCert, err | ||
} | ||
|
||
// Sign the cert | ||
func createCert(template, parent *x509.Certificate, pub, parentPriv interface{}) ( | ||
cert *x509.Certificate, certPEM []byte, err error) { | ||
certDER, err := x509.CreateCertificate(rand.Reader, template, parent, pub, parentPriv) | ||
if err != nil { | ||
return | ||
} | ||
cert, err = x509.ParseCertificate(certDER) | ||
if err != nil { | ||
return | ||
} | ||
b := pem.Block{Type: "CERTIFICATE", Bytes: certDER} | ||
certPEM = pem.EncodeToMemory(&b) | ||
return | ||
} | ||
|
||
func createCA(org string, hosts []string, notAfter time.Time) (*rsa.PrivateKey, *x509.Certificate, []byte, error) { | ||
rootKey, err := rsa.GenerateKey(rand.Reader, 2048) | ||
if err != nil { | ||
return nil, nil, nil, errors.Wrap(err, "failed to generate random key") | ||
} | ||
|
||
rootCertTmpl, err := createCACertTemplate(org, hosts, notAfter) | ||
if err != nil { | ||
return nil, nil, nil, errors.Wrap(err, "failed to generate CA cert") | ||
} | ||
|
||
rootCert, rootCertPEM, err := createCert(rootCertTmpl, rootCertTmpl, &rootKey.PublicKey, rootKey) | ||
if err != nil { | ||
return nil, nil, nil, errors.Wrap(err, "failed to sign CA cert") | ||
} | ||
return rootKey, rootCert, rootCertPEM, nil | ||
} | ||
|
||
// CreateCerts creates and returns a CA certificate and certificate and | ||
// key for the server | ||
func CreateCerts(org string, hosts []string, notAfter time.Time) (serverKey, serverCert, caCert []byte, err error) { | ||
// Create a CA certificate and private key | ||
caKey, caCertificate, caCertificatePEM, err := createCA(org, hosts, notAfter) | ||
if err != nil { | ||
return nil, nil, nil, err | ||
} | ||
|
||
// Create the private key | ||
servKey, err := rsa.GenerateKey(rand.Reader, 2048) | ||
if err != nil { | ||
return nil, nil, nil, errors.Wrap(err, "failed to generate random key") | ||
} | ||
servCertTemplate, err := createServerCertTemplate(org, hosts, notAfter) | ||
if err != nil { | ||
return nil, nil, nil, errors.Wrap(err, "failed to create server cert template") | ||
} | ||
|
||
// create a certificate wrapping the public key, sign it with the CA private key | ||
_, servCertPEM, err := createCert(servCertTemplate, caCertificate, &servKey.PublicKey, caKey) | ||
if err != nil { | ||
return nil, nil, nil, errors.Wrap(err, "failed to sign server cert") | ||
} | ||
servKeyPEM := pem.EncodeToMemory(&pem.Block{ | ||
Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(servKey), | ||
}) | ||
return servKeyPEM, servCertPEM, caCertificatePEM, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package tls | ||
|
||
import ( | ||
"crypto/x509" | ||
"encoding/pem" | ||
"testing" | ||
"time" | ||
|
||
"github.com/pkg/errors" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestCreateCerts(t *testing.T) { | ||
t.Run("test create certs", func(t *testing.T) { | ||
sKey, serverCertPEM, caCertBytes, err := CreateCerts("test-org", []string{"test-host"}, time.Now().AddDate(1, 0, 0)) | ||
assert.NoError(t, err) | ||
p, _ := pem.Decode(sKey) | ||
assert.Equal(t, "RSA PRIVATE KEY", p.Type) | ||
key, err := x509.ParsePKCS1PrivateKey(p.Bytes) | ||
assert.NoError(t, err) | ||
err = key.Validate() | ||
assert.NoError(t, err) | ||
sCert, err := validCertificate(serverCertPEM, t) | ||
assert.NoError(t, err) | ||
caParsedCert, err := validCertificate(caCertBytes, t) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "test-host", caParsedCert.DNSNames[0]) | ||
err = sCert.CheckSignatureFrom(caParsedCert) | ||
assert.NoError(t, err) | ||
}) | ||
} | ||
|
||
func validCertificate(cert []byte, t *testing.T) (*x509.Certificate, error) { | ||
t.Helper() | ||
const certificate = "CERTIFICATE" | ||
caCert, _ := pem.Decode(cert) | ||
if caCert.Type != certificate { | ||
return nil, errors.Errorf("CERT type mismatch, got %s, want: %s", caCert.Type, certificate) | ||
} | ||
parsedCert, err := x509.ParseCertificate(caCert.Bytes) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to parse cert") | ||
} | ||
if parsedCert.SignatureAlgorithm != x509.SHA256WithRSA { | ||
return nil, errors.Errorf("signature not match. Got: %s, want: %s", parsedCert.SignatureAlgorithm, x509.SHA256WithRSA) | ||
} | ||
return parsedCert, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package eventbus | ||
|
||
import ( | ||
"github.com/pkg/errors" | ||
|
||
"github.com/argoproj/argo-events/pkg/apis/eventbus/v1alpha1" | ||
) | ||
|
||
// ValidateEventBus accepts an EventBus and performs validation against it | ||
func ValidateEventBus(eb *v1alpha1.EventBus) error { | ||
if eb.Spec.NATS != nil { | ||
if eb.Spec.NATS.Native != nil && eb.Spec.NATS.Exotic != nil { | ||
return errors.New("\"spec.nats.native\" and \"spec.nats.exotic\" can not be defined together") | ||
} | ||
if eb.Spec.NATS.Exotic != nil { | ||
e := eb.Spec.NATS.Exotic | ||
if e.ClusterID == nil { | ||
return errors.New("\"spec.nats.exotic.clusterID\" is missing") | ||
} | ||
if e.URL == "" { | ||
return errors.New("\"spec.nats.exotic.url\" is missing") | ||
} | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package eventbus | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
|
||
"github.com/argoproj/argo-events/common" | ||
"github.com/argoproj/argo-events/pkg/apis/eventbus/v1alpha1" | ||
) | ||
|
||
var ( | ||
testEventBus = &v1alpha1.EventBus{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Namespace: "test-ns", | ||
Name: common.DefaultEventBusName, | ||
}, | ||
Spec: v1alpha1.EventBusSpec{ | ||
NATS: &v1alpha1.NATSBus{ | ||
Native: &v1alpha1.NativeStrategy{ | ||
Auth: &v1alpha1.AuthStrategyToken, | ||
}, | ||
}, | ||
}, | ||
} | ||
) | ||
|
||
func TestValidate(t *testing.T) { | ||
t.Run("test good eventbus", func(t *testing.T) { | ||
err := ValidateEventBus(testEventBus) | ||
assert.NoError(t, err) | ||
}) | ||
|
||
t.Run("test native exotic conflicting eventbus", func(t *testing.T) { | ||
eb := testEventBus.DeepCopy() | ||
eb.Spec.NATS.Exotic = &v1alpha1.NATSConfig{} | ||
err := ValidateEventBus(eb) | ||
assert.Error(t, err) | ||
assert.True(t, strings.Contains(err.Error(), "can not be defined together")) | ||
}) | ||
|
||
t.Run("test exotic eventbus no clusterID", func(t *testing.T) { | ||
eb := testEventBus.DeepCopy() | ||
eb.Spec.NATS.Native = nil | ||
eb.Spec.NATS.Exotic = &v1alpha1.NATSConfig{} | ||
err := ValidateEventBus(eb) | ||
assert.Error(t, err) | ||
assert.True(t, strings.Contains(err.Error(), "\"spec.nats.exotic.clusterID\" is missing")) | ||
}) | ||
|
||
t.Run("test exotic eventbus empty URL", func(t *testing.T) { | ||
eb := testEventBus.DeepCopy() | ||
eb.Spec.NATS.Native = nil | ||
cID := "test-cluster-id" | ||
eb.Spec.NATS.Exotic = &v1alpha1.NATSConfig{ | ||
ClusterID: &cID, | ||
} | ||
err := ValidateEventBus(eb) | ||
assert.Error(t, err) | ||
assert.True(t, strings.Contains(err.Error(), "\"spec.nats.exotic.url\" is missing")) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.