mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
Added Support for CSR in x509_decode()
(#6744)
* fixes Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * err fix Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * added kuttl tests Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * updated files for test Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * updated tests Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * NIT Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * Update test/conformance/kuttl/validate/clusterpolicy/standard/enforce/csr/01-policy.yaml Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> Signed-off-by: Vishal Choudhary <contactvishaltech@gmail.com> * updated kuttl tests Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * added tests Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * updated readme Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * added requested changes Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * refactor Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * refactor Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * changes Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * refactor Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> Signed-off-by: Vishal Choudhary <contactvishaltech@gmail.com> Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
e5a9148a75
commit
77bb5aca12
9 changed files with 191 additions and 41 deletions
|
@ -3,6 +3,7 @@ package jmespath
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
|
@ -1059,58 +1060,79 @@ func jpRandom(arguments []interface{}) (interface{}, error) {
|
|||
return ans, nil
|
||||
}
|
||||
|
||||
func jpX509Decode(arguments []interface{}) (interface{}, error) {
|
||||
res := make(map[string]interface{})
|
||||
input, err := validateArg(x509_decode, arguments, 0, reflect.String)
|
||||
if err != nil {
|
||||
func encode[T any](in T) (interface{}, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(buf)
|
||||
if err := enc.Encode(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p, _ := pem.Decode([]byte(input.String()))
|
||||
if p == nil {
|
||||
return res, errors.New("invalid certificate")
|
||||
res := map[string]interface{}{}
|
||||
if err := json.Unmarshal(buf.Bytes(), &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
cert, err := x509.ParseCertificate(p.Bytes)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if fmt.Sprint(cert.PublicKeyAlgorithm) == "RSA" {
|
||||
spki := cryptobyte.String(cert.RawSubjectPublicKeyInfo)
|
||||
func jpX509Decode(arguments []interface{}) (interface{}, error) {
|
||||
parseSubjectPublicKeyInfo := func(data []byte) (*rsa.PublicKey, error) {
|
||||
spki := cryptobyte.String(data)
|
||||
if !spki.ReadASN1(&spki, cryptobyte_asn1.SEQUENCE) {
|
||||
return res, errors.New("writing asn.1 element to 'spki' failed")
|
||||
return nil, errors.New("writing asn.1 element to 'spki' failed")
|
||||
}
|
||||
var pkAISeq cryptobyte.String
|
||||
if !spki.ReadASN1(&pkAISeq, cryptobyte_asn1.SEQUENCE) {
|
||||
return res, errors.New("writing asn.1 element to 'pkAISeq' failed")
|
||||
return nil, errors.New("writing asn.1 element to 'pkAISeq' failed")
|
||||
}
|
||||
var spk asn1.BitString
|
||||
if !spki.ReadASN1BitString(&spk) {
|
||||
return res, errors.New("writing asn.1 bit string to 'spk' failed")
|
||||
return nil, errors.New("writing asn.1 bit string to 'spk' failed")
|
||||
}
|
||||
kk, err := x509.ParsePKCS1PublicKey(spk.Bytes)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
cert.PublicKey = PublicKey{
|
||||
N: kk.N.String(),
|
||||
E: kk.E,
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(buf)
|
||||
err = enc.Encode(cert)
|
||||
if err != nil {
|
||||
return res, err
|
||||
if kk, err := x509.ParsePKCS1PublicKey(spk.Bytes); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return kk, nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(buf.Bytes(), &res); err != nil {
|
||||
return res, err
|
||||
if input, err := validateArg(x509_decode, arguments, 0, reflect.String); err != nil {
|
||||
return nil, err
|
||||
} else if block, _ := pem.Decode([]byte(input.String())); block == nil {
|
||||
return nil, errors.New("failed to decode PEM block")
|
||||
} else {
|
||||
switch block.Type {
|
||||
case "CERTIFICATE":
|
||||
var cert *x509.Certificate
|
||||
if cert, err = x509.ParseCertificate(block.Bytes); err != nil {
|
||||
return nil, err
|
||||
} else if cert.PublicKeyAlgorithm != x509.RSA {
|
||||
return nil, errors.New("certificate should use rsa algorithm")
|
||||
} else if pk, err := parseSubjectPublicKeyInfo(cert.RawSubjectPublicKeyInfo); err != nil {
|
||||
return nil, errors.New("failed to parse subject public key info")
|
||||
} else {
|
||||
cert.PublicKey = PublicKey{
|
||||
N: pk.N.String(),
|
||||
E: pk.E,
|
||||
}
|
||||
return encode(cert)
|
||||
}
|
||||
case "CERTIFICATE REQUEST":
|
||||
var csr *x509.CertificateRequest
|
||||
if csr, err = x509.ParseCertificateRequest(block.Bytes); err != nil {
|
||||
return nil, err
|
||||
} else if csr.PublicKeyAlgorithm != x509.RSA {
|
||||
return nil, errors.New("certificate should use rsa algorithm")
|
||||
} else if pk, err := parseSubjectPublicKeyInfo(csr.RawSubjectPublicKeyInfo); err != nil {
|
||||
return nil, errors.New("failed to parse subject public key info")
|
||||
} else {
|
||||
csr.PublicKey = PublicKey{
|
||||
N: pk.N.String(),
|
||||
E: pk.E,
|
||||
}
|
||||
return encode(csr)
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("PEM block neither contains a CERTIFICATE or CERTIFICATE REQUEST")
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func jpImageNormalize(configuration config.Configuration) gojmespath.JpFunction {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,6 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- policy.yaml
|
||||
assert:
|
||||
- policy-ready.yaml
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- csr.yaml
|
||||
assert:
|
||||
- csr-mutated.yaml
|
|
@ -0,0 +1,12 @@
|
|||
## Description
|
||||
|
||||
This test mainly verifies that the JMESPath path for x509decode works for CSR does work properly.
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
1. A policy is created to check Certificate Signing Requests and a policy that adds labels to the CSR.
|
||||
2. A CSR Resource is created and it is verified that it has the same labels.
|
||||
|
||||
## Reference Issue(s)
|
||||
|
||||
5858
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: certificates.k8s.io/v1
|
||||
kind: CertificateSigningRequest
|
||||
metadata:
|
||||
name: myuser
|
||||
labels:
|
||||
name: angela
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: certificates.k8s.io/v1
|
||||
kind: CertificateSigningRequest
|
||||
metadata:
|
||||
name: myuser
|
||||
spec:
|
||||
request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZqQ0NBVDRDQVFBd0VURVBNQTBHQTFVRUF3d0dZVzVuWld4aE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQTByczhJTHRHdTYxakx2dHhWTTJSVlRWMDNHWlJTWWw0dWluVWo4RElaWjBOCnR2MUZtRVFSd3VoaUZsOFEzcWl0Qm0wMUFSMkNJVXBGd2ZzSjZ4MXF3ckJzVkhZbGlBNVhwRVpZM3ExcGswSDQKM3Z3aGJlK1o2MVNrVHF5SVBYUUwrTWM5T1Nsbm0xb0R2N0NtSkZNMUlMRVI3QTVGZnZKOEdFRjJ6dHBoaUlFMwpub1dtdHNZb3JuT2wzc2lHQ2ZGZzR4Zmd4eW8ybmlneFNVekl1bXNnVm9PM2ttT0x1RVF6cXpkakJ3TFJXbWlECklmMXBMWnoyalVnald4UkhCM1gyWnVVV1d1T09PZnpXM01LaE8ybHEvZi9DdS8wYk83c0x0MCt3U2ZMSU91TFcKcW90blZtRmxMMytqTy82WDNDKzBERHk5aUtwbXJjVDBnWGZLemE1dHJRSURBUUFCb0FBd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBR05WdmVIOGR4ZzNvK21VeVRkbmFjVmQ1N24zSkExdnZEU1JWREkyQTZ1eXN3ZFp1L1BVCkkwZXpZWFV0RVNnSk1IRmQycVVNMjNuNVJsSXJ3R0xuUXFISUh5VStWWHhsdnZsRnpNOVpEWllSTmU3QlJvYXgKQVlEdUI5STZXT3FYbkFvczFqRmxNUG5NbFpqdU5kSGxpT1BjTU1oNndLaTZzZFhpVStHYTJ2RUVLY01jSVUyRgpvU2djUWdMYTk0aEpacGk3ZnNMdm1OQUxoT045UHdNMGM1dVJVejV4T0dGMUtCbWRSeEgvbUNOS2JKYjFRQm1HCkkwYitEUEdaTktXTU0xMzhIQXdoV0tkNjVoVHdYOWl4V3ZHMkh4TG1WQzg0L1BHT0tWQW9FNkpsYWFHdTlQVmkKdjlOSjVaZlZrcXdCd0hKbzZXdk9xVlA3SVFjZmg3d0drWm89Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
|
||||
signerName: kubernetes.io/kube-apiserver-client
|
||||
expirationSeconds: 86400
|
||||
usages:
|
||||
- client auth
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: validate-csr
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
||||
---
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: mutate-csr
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
|
@ -0,0 +1,46 @@
|
|||
apiVersion: kyverno.io/v2beta1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: validate-csr
|
||||
spec:
|
||||
background: false
|
||||
validationFailureAction: Enforce
|
||||
rules:
|
||||
- name: csr
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- CertificateSigningRequest
|
||||
validate:
|
||||
message: >-
|
||||
CSR created by {{ request.userInfo | to_string(@) }}
|
||||
with ClusterRoles {{ request.clusterRoles | to_string(@) }}
|
||||
and Roles {{ request.roles | to_string(@) }}.
|
||||
Subjects and groups requested are "{{ x509_decode(base64_decode(request.object.spec.request)).Subject | to_string(@) }}"
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
- key: "{{ x509_decode(base64_decode(request.object.spec.request)).Subject.CommonName }}"
|
||||
operator: NotEquals
|
||||
value: "angela"
|
||||
---
|
||||
apiVersion: kyverno.io/v2beta1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: mutate-csr
|
||||
spec:
|
||||
background: false
|
||||
validationFailureAction: Enforce
|
||||
rules:
|
||||
- name: csr
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- CertificateSigningRequest
|
||||
mutate:
|
||||
patchStrategicMerge:
|
||||
metadata:
|
||||
labels:
|
||||
name: "{{ x509_decode(base64_decode(request.object.spec.request)).Subject.CommonName | to_string(@) }}"
|
Loading…
Reference in a new issue