feat: kubesphere 4.0 (#6115)

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

---------

Signed-off-by: ci-bot <ci-bot@kubesphere.io>
Co-authored-by: ks-ci-bot <ks-ci-bot@example.com>
Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
KubeSphere CI Bot
2024-09-06 11:05:52 +08:00
committed by GitHub
parent b5015ec7b9
commit 447a51f08b
8557 changed files with 546695 additions and 1146174 deletions

View File

@@ -6,11 +6,13 @@ package topdown
import (
"bytes"
"crypto"
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/json"
@@ -20,8 +22,9 @@ import (
"os"
"strings"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/internal/jwx/jwk"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/topdown/builtins"
"github.com/open-policy-agent/opa/util"
)
@@ -38,7 +41,8 @@ const (
blockTypeRSAPrivateKey = "RSA PRIVATE KEY"
// blockTypeRSAPrivateKey indicates this PEM block contains a RSA private key.
// Exported for tests.
blockTypePrivateKey = "PRIVATE KEY"
blockTypePrivateKey = "PRIVATE KEY"
blockTypeEcPrivateKey = "EC PRIVATE KEY"
)
func builtinCryptoX509ParseCertificates(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
@@ -52,7 +56,7 @@ func builtinCryptoX509ParseCertificates(_ BuiltinContext, operands []*ast.Term,
return err
}
v, err := ast.InterfaceToValue(certs)
v, err := ast.InterfaceToValue(extendCertificates(certs))
if err != nil {
return err
}
@@ -60,6 +64,28 @@ func builtinCryptoX509ParseCertificates(_ BuiltinContext, operands []*ast.Term,
return iter(ast.NewTerm(v))
}
// extendedCert is a wrapper around x509.Certificate that adds additional fields for JSON serialization.
type extendedCert struct {
x509.Certificate
URIStrings []string
}
func extendCertificates(certs []*x509.Certificate) []extendedCert {
// add a field to certs containing the URIs as strings
processedCerts := make([]extendedCert, len(certs))
for i, cert := range certs {
processedCerts[i].Certificate = *cert
if cert.URIs != nil {
processedCerts[i].URIStrings = make([]string, len(cert.URIs))
for j, uri := range cert.URIs {
processedCerts[i].URIStrings[j] = uri.String()
}
}
}
return processedCerts
}
func builtinCryptoX509ParseAndVerifyCertificates(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
a := operands[0].Value
@@ -83,7 +109,7 @@ func builtinCryptoX509ParseAndVerifyCertificates(_ BuiltinContext, operands []*a
return iter(invalid)
}
value, err := ast.InterfaceToValue(verified)
value, err := ast.InterfaceToValue(extendCertificates(verified))
if err != nil {
return err
}
@@ -96,6 +122,29 @@ func builtinCryptoX509ParseAndVerifyCertificates(_ BuiltinContext, operands []*a
return iter(valid)
}
func builtinCryptoX509ParseKeyPair(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
certificate, err := builtins.StringOperand(operands[0].Value, 1)
if err != nil {
return err
}
key, err := builtins.StringOperand(operands[1].Value, 1)
if err != nil {
return err
}
certs, err := getTLSx509KeyPairFromString([]byte(certificate), []byte(key))
if err != nil {
return err
}
v, err := ast.InterfaceToValue(certs)
if err != nil {
return err
}
return iter(ast.NewTerm(v))
}
func builtinCryptoX509ParseCertificateRequest(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
input, err := builtins.StringOperand(operands[0].Value, 1)
if err != nil {
@@ -144,7 +193,8 @@ func builtinCryptoX509ParseCertificateRequest(_ BuiltinContext, operands []*ast.
return iter(ast.NewTerm(v))
}
func builtinCryptoX509ParseRSAPrivateKey(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
func builtinCryptoJWKFromPrivateKey(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
var x interface{}
a := operands[0].Value
input, err := builtins.StringOperand(a, 1)
@@ -153,23 +203,83 @@ func builtinCryptoX509ParseRSAPrivateKey(_ BuiltinContext, operands []*ast.Term,
}
// get the raw private key
rawKey, err := getRSAPrivateKeyFromString(string(input))
pemDataString := string(input)
if pemDataString == "" {
return fmt.Errorf("input PEM data was empty")
}
// This built in must be supplied a valid PEM or base64 encoded string.
// If the input is not a PEM string, attempt to decode b64.
// If the base64 decode fails - this is an error
if !strings.HasPrefix(pemDataString, "-----BEGIN") {
bs, err := base64.StdEncoding.DecodeString(pemDataString)
if err != nil {
return err
}
pemDataString = string(bs)
}
rawKeys, err := getPrivateKeysFromPEMData(pemDataString)
if err != nil {
return err
}
rsaPrivateKey, err := jwk.New(rawKey)
if len(rawKeys) == 0 {
return iter(ast.NullTerm())
}
key, err := jwk.New(rawKeys[0])
if err != nil {
return err
}
jsonKey, err := json.Marshal(rsaPrivateKey)
jsonKey, err := json.Marshal(key)
if err != nil {
return err
}
if err := util.UnmarshalJSON(jsonKey, &x); err != nil {
return err
}
value, err := ast.InterfaceToValue(x)
if err != nil {
return err
}
return iter(ast.NewTerm(value))
}
func builtinCryptoParsePrivateKeys(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
a := operands[0].Value
input, err := builtins.StringOperand(a, 1)
if err != nil {
return err
}
if string(input) == "" {
return iter(ast.NullTerm())
}
// get the raw private key
rawKeys, err := getPrivateKeysFromPEMData(string(input))
if err != nil {
return err
}
if len(rawKeys) == 0 {
return iter(ast.NewTerm(ast.NewArray()))
}
bs, err := json.Marshal(rawKeys)
if err != nil {
return err
}
var x interface{}
if err := util.UnmarshalJSON(jsonKey, &x); err != nil {
if err := util.UnmarshalJSON(bs, &x); err != nil {
return err
}
@@ -249,6 +359,24 @@ func builtinCryptoHmacSha512(_ BuiltinContext, operands []*ast.Term, iter func(*
return hmacHelper(operands, iter, sha512.New)
}
func builtinCryptoHmacEqual(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
a1 := operands[0].Value
mac1, err := builtins.StringOperand(a1, 1)
if err != nil {
return err
}
a2 := operands[1].Value
mac2, err := builtins.StringOperand(a2, 2)
if err != nil {
return err
}
res := hmac.Equal([]byte(mac1), []byte(mac2))
return iter(ast.BooleanTerm(res))
}
func init() {
RegisterBuiltinFunc(ast.CryptoX509ParseCertificates.Name, builtinCryptoX509ParseCertificates)
RegisterBuiltinFunc(ast.CryptoX509ParseAndVerifyCertificates.Name, builtinCryptoX509ParseAndVerifyCertificates)
@@ -256,11 +384,14 @@ func init() {
RegisterBuiltinFunc(ast.CryptoSha1.Name, builtinCryptoSha1)
RegisterBuiltinFunc(ast.CryptoSha256.Name, builtinCryptoSha256)
RegisterBuiltinFunc(ast.CryptoX509ParseCertificateRequest.Name, builtinCryptoX509ParseCertificateRequest)
RegisterBuiltinFunc(ast.CryptoX509ParseRSAPrivateKey.Name, builtinCryptoX509ParseRSAPrivateKey)
RegisterBuiltinFunc(ast.CryptoX509ParseRSAPrivateKey.Name, builtinCryptoJWKFromPrivateKey)
RegisterBuiltinFunc(ast.CryptoParsePrivateKeys.Name, builtinCryptoParsePrivateKeys)
RegisterBuiltinFunc(ast.CryptoX509ParseKeyPair.Name, builtinCryptoX509ParseKeyPair)
RegisterBuiltinFunc(ast.CryptoHmacMd5.Name, builtinCryptoHmacMd5)
RegisterBuiltinFunc(ast.CryptoHmacSha1.Name, builtinCryptoHmacSha1)
RegisterBuiltinFunc(ast.CryptoHmacSha256.Name, builtinCryptoHmacSha256)
RegisterBuiltinFunc(ast.CryptoHmacSha512.Name, builtinCryptoHmacSha512)
RegisterBuiltinFunc(ast.CryptoHmacEqual.Name, builtinCryptoHmacEqual)
}
func verifyX509CertificateChain(certs []*x509.Certificate) ([]*x509.Certificate, error) {
@@ -334,43 +465,56 @@ func getX509CertsFromPem(pemBlocks []byte) ([]*x509.Certificate, error) {
return x509.ParseCertificates(decodedCerts)
}
func getRSAPrivateKeyFromString(key string) (interface{}, error) {
// if the input is PEM handle that
if strings.HasPrefix(key, "-----BEGIN") {
return getRSAPrivateKeyFromPEM([]byte(key))
func getPrivateKeysFromPEMData(pemData string) ([]crypto.PrivateKey, error) {
pemBlockString := pemData
var validPrivateKeys []crypto.PrivateKey
// if the input is base64, decode it
bs, err := base64.StdEncoding.DecodeString(pemBlockString)
if err == nil {
pemBlockString = string(bs)
}
bs = []byte(pemBlockString)
// assume input is base64 if not PEM
b64, err := base64.StdEncoding.DecodeString(key)
if err != nil {
return nil, err
for len(bs) > 0 {
inputLen := len(bs)
var block *pem.Block
block, bs = pem.Decode(bs)
if block == nil && len(bs) == 0 {
break
}
// should only happen if end of input is not a valid PEM block. See TestParseRSAPrivateKeyVariedPemInput.
if inputLen == len(bs) {
break
}
if block == nil {
continue
}
switch block.Type {
case blockTypeRSAPrivateKey:
parsedKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
validPrivateKeys = append(validPrivateKeys, parsedKey)
case blockTypePrivateKey:
parsedKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
validPrivateKeys = append(validPrivateKeys, parsedKey)
case blockTypeEcPrivateKey:
parsedKey, err := x509.ParseECPrivateKey(block.Bytes)
if err != nil {
return nil, err
}
validPrivateKeys = append(validPrivateKeys, parsedKey)
}
}
return getRSAPrivateKeyFromPEM(b64)
}
func getRSAPrivateKeyFromPEM(pemBlocks []byte) (interface{}, error) {
// decode the pem into the Block struct
p, _ := pem.Decode(pemBlocks)
if p == nil {
return nil, fmt.Errorf("failed to parse PEM block containing the key")
}
// if the key is in PKCS1 format
if p.Type == blockTypeRSAPrivateKey {
return x509.ParsePKCS1PrivateKey(p.Bytes)
}
// if the key is in PKCS8 format
if p.Type == blockTypePrivateKey {
return x509.ParsePKCS8PrivateKey(p.Bytes)
}
// unsupported key format
return nil, fmt.Errorf("PEM block type is '%s', expected %s or %s", p.Type, blockTypeRSAPrivateKey,
blockTypePrivateKey)
return validPrivateKeys, nil
}
// addCACertsFromFile adds CA certificates from filePath into the given pool.
@@ -406,7 +550,7 @@ func addCACertsFromBytes(pool *x509.CertPool, pemBytes []byte) (*x509.CertPool,
return pool, nil
}
// addCACertsFromBytes adds CA certificates from the environment variable named
// addCACertsFromEnv adds CA certificates from the environment variable named
// by envName into the given pool. If pool is nil, it creates a new x509.CertPool.
// pool is returned.
func addCACertsFromEnv(pool *x509.CertPool, envName string) (*x509.CertPool, error) {
@@ -428,6 +572,60 @@ func readCertFromFile(localCertFile string) ([]byte, error) {
return certPEM, nil
}
func getTLSx509KeyPairFromString(certPemBlock []byte, keyPemBlock []byte) (*tls.Certificate, error) {
if !strings.HasPrefix(string(certPemBlock), "-----BEGIN") {
s, err := base64.StdEncoding.DecodeString(string(certPemBlock))
if err != nil {
return nil, err
}
certPemBlock = s
}
if !strings.HasPrefix(string(keyPemBlock), "-----BEGIN") {
s, err := base64.StdEncoding.DecodeString(string(keyPemBlock))
if err != nil {
return nil, err
}
keyPemBlock = s
}
// we assume it a DER certificate and try to convert it to a PEM.
if !bytes.HasPrefix(certPemBlock, []byte("-----BEGIN")) {
pemBlock := &pem.Block{
Type: "CERTIFICATE",
Bytes: certPemBlock,
}
var buf bytes.Buffer
if err := pem.Encode(&buf, pemBlock); err != nil {
return nil, err
}
certPemBlock = buf.Bytes()
}
// we assume it a DER key and try to convert it to a PEM.
if !bytes.HasPrefix(keyPemBlock, []byte("-----BEGIN")) {
pemBlock := &pem.Block{
Type: "PRIVATE KEY",
Bytes: keyPemBlock,
}
var buf bytes.Buffer
if err := pem.Encode(&buf, pemBlock); err != nil {
return nil, err
}
keyPemBlock = buf.Bytes()
}
cert, err := tls.X509KeyPair(certPemBlock, keyPemBlock)
if err != nil {
return nil, err
}
return &cert, nil
}
// ReadKeyFromFile reads a key from file
func readKeyFromFile(localKeyFile string) ([]byte, error) {
// Read in the cert file