Skip to content

Commit

Permalink
TLS artifacts: parse all certs in crt file, return all authinfo in ku…
Browse files Browse the repository at this point in the history
…beconfig
  • Loading branch information
vrutkovs committed Jul 10, 2024
1 parent 6b506c0 commit 40ee799
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 90 deletions.
110 changes: 50 additions & 60 deletions pkg/certs/cert-inspection/certgraphanalysis/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,34 @@ import (
"github.com/openshift/library-go/pkg/certs/cert-inspection/certgraphapi"
certificatesv1 "k8s.io/api/certificates/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/util/cert"
)

func InspectSecret(obj *corev1.Secret) (*certgraphapi.CertKeyPair, error) {
resourceString := fmt.Sprintf("secrets/%s[%s]", obj.Name, obj.Namespace)
func InspectSecret(obj *corev1.Secret) ([]*certgraphapi.CertKeyPair, error) {
tlsCrt, isTLS := obj.Data["tls.crt"]
if !isTLS {
if !isTLS || len(tlsCrt) == 0 {
if detail, err := InspectSecretAsKubeConfig(obj); err == nil {
return detail, nil
}
return nil, nil
}
//fmt.Printf("%s - tls (%v)\n", resourceString, obj.CreationTimestamp.UTC())
if len(tlsCrt) == 0 {
return nil, fmt.Errorf("%s MISSING tls.crt content\n", resourceString)
}

certificates, err := cert.ParseCertsPEM([]byte(tlsCrt))
if err != nil {
return nil, err
}
for _, certificate := range certificates {
detail, err := toCertKeyPair(certificate)
if err != nil {
return nil, err
}
detail = addSecretLocation(detail, obj.Namespace, obj.Name)
return detail, nil
}
return nil, fmt.Errorf("didn't see that coming")
return extractCertKeyPairsFromBytes("secret", &obj.ObjectMeta, tlsCrt)
}

func inspectCSR(resourceString, objName string, certificate []byte) (*certgraphapi.CertKeyPair, error) {
func extractCertKeyPairsFromBytes(resourceType string, obj *metav1.ObjectMeta, certificate []byte) ([]*certgraphapi.CertKeyPair, error) {
resourceString := ""
if obj != nil {
resourceString = fmt.Sprintf("%s/%s[%s]", resourceType, obj.Name, obj.Namespace)
}
if len(certificate) == 0 {
return nil, fmt.Errorf("%s MISSING issued certificate\n", resourceString)
}

certKeyPairDetails := []*certgraphapi.CertKeyPair{}
certificates, err := cert.ParseCertsPEM([]byte(certificate))
if err != nil {
return nil, err
Expand All @@ -54,31 +43,31 @@ func inspectCSR(resourceString, objName string, certificate []byte) (*certgrapha
if err != nil {
return nil, err
}
return detail, nil
if resourceType == "secret" && obj != nil {
detail = addSecretLocation(detail, obj.Namespace, obj.Name)
}
certKeyPairDetails = append(certKeyPairDetails, detail)
}
return nil, fmt.Errorf("didn't see that coming")
return certKeyPairDetails, nil
}

func InspectCSR(obj *certificatesv1.CertificateSigningRequest) (*certgraphapi.CertKeyPair, error) {
resourceString := fmt.Sprintf("csr/%s[%s]", obj.Name, obj.Namespace)
return inspectCSR(resourceString, obj.Name, obj.Status.Certificate)
func InspectCSR(obj *certificatesv1.CertificateSigningRequest) ([]*certgraphapi.CertKeyPair, error) {
return extractCertKeyPairsFromBytes("csr", &obj.ObjectMeta, obj.Status.Certificate)
}

func InspectConfigMap(obj *corev1.ConfigMap) (*certgraphapi.CertificateAuthorityBundle, error) {
caBundle, ok := obj.Data["ca-bundle.crt"]
if !ok {
if detail, err := InspectConfigMapAsKubeConfig(obj); err == nil {
return detail, nil
}
return nil, nil
if details, err := InspectConfigMapAsKubeConfig(obj); err == nil {
return details, nil
}
if len(caBundle) == 0 {

caBundle, ok := obj.Data["ca-bundle.crt"]
if !ok || len(caBundle) == 0 {
return nil, nil
}

certificates, err := cert.ParseCertsPEM([]byte(caBundle))
if err != nil {
return nil, err
return nil, nil
}
caBundleDetail, err := toCABundle(certificates)
if err != nil {
Expand All @@ -104,17 +93,17 @@ func extractKubeConfigFromConfigMap(obj *corev1.ConfigMap) (*rest.Config, error)
return nil, nil
}

func extractKubeConfigFromSecret(obj *corev1.Secret) (*rest.Config, error) {
func extractKubeConfigFromSecret(obj *corev1.Secret) (*clientcmdapi.Config, error) {
if obj == nil {
return nil, fmt.Errorf("empty object")
}
for _, v := range obj.Data {
kubeConfig, err := clientcmd.NewClientConfigFromBytes(v)
clientConfig, err := clientcmd.NewClientConfigFromBytes(v)
if err != nil {
continue
}
if clientConfig, err := kubeConfig.ClientConfig(); err == nil {
return clientConfig, nil
if kubeConfig, err := clientConfig.RawConfig(); err == nil && kubeConfig.CurrentContext != "" {
return &kubeConfig, nil
}
}
return nil, nil
Expand All @@ -126,7 +115,7 @@ func GetCAFromKubeConfig(kubeConfig *rest.Config, namespace, name string) (*cert
}
certificates, err := cert.ParseCertsPEM(kubeConfig.CAData)
if err != nil {
return nil, err
return nil, nil
}
caBundleDetail, err := toCABundle(certificates)
if err != nil {
Expand All @@ -138,39 +127,40 @@ func GetCAFromKubeConfig(kubeConfig *rest.Config, namespace, name string) (*cert
return caBundleDetail, nil
}

func GetCertKeyPairFromKubeConfig(kubeConfig *rest.Config, namespace, name string) (*certgraphapi.CertKeyPair, error) {
if kubeConfig == nil {
return nil, fmt.Errorf("empty kubeconfig")
}
certificates, err := cert.ParseCertsPEM(kubeConfig.CertData)
if err != nil {
return nil, err
}
for _, certificate := range certificates {
detail, err := toCertKeyPair(certificate)
if err != nil {
return nil, err
}
if len(namespace) > 0 && len(name) > 0 {
detail = addSecretLocation(detail, namespace, name)
}
return detail, nil
func GetCertKeyPairsFromKubeConfig(authInfo *clientcmdapi.AuthInfo, obj *metav1.ObjectMeta) ([]*certgraphapi.CertKeyPair, error) {
if authInfo == nil {
return nil, fmt.Errorf("empty authinfo")
}
return nil, fmt.Errorf("didn't see that coming")
return extractCertKeyPairsFromBytes("secret", obj, authInfo.ClientCertificateData)
}

func InspectConfigMapAsKubeConfig(obj *corev1.ConfigMap) (*certgraphapi.CertificateAuthorityBundle, error) {
kubeConfig, err := extractKubeConfigFromConfigMap(obj)
if err != nil {
return nil, err
}
if kubeConfig == nil {
return nil, fmt.Errorf("empty kubeconfig")
}

return GetCAFromKubeConfig(kubeConfig, obj.Namespace, obj.Name)
}

func InspectSecretAsKubeConfig(obj *corev1.Secret) (*certgraphapi.CertKeyPair, error) {
func InspectSecretAsKubeConfig(obj *corev1.Secret) ([]*certgraphapi.CertKeyPair, error) {
kubeConfig, err := extractKubeConfigFromSecret(obj)
if err != nil {
return nil, err
}
return GetCertKeyPairFromKubeConfig(kubeConfig, obj.Namespace, obj.Name)
if kubeConfig == nil {
return nil, fmt.Errorf("empty kubeconfig")
}
certKeyPairInfos := []*certgraphapi.CertKeyPair{}
for _, v := range kubeConfig.AuthInfos {
certKeyPairInfo, err := GetCertKeyPairsFromKubeConfig(v, &obj.ObjectMeta)
if err != nil {
continue
}
certKeyPairInfos = append(certKeyPairInfos, certKeyPairInfo...)
}
return certKeyPairInfos, nil
}
9 changes: 5 additions & 4 deletions pkg/certs/cert-inspection/certgraphanalysis/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ func gatherFilteredCerts(ctx context.Context, kubeClient kubernetes.Interface, a
continue
}
options.rewriteCABundle(configMap.ObjectMeta, details)

caBundles = append(caBundles, details)

inClusterResourceData.CertificateAuthorityBundles = append(inClusterResourceData.CertificateAuthorityBundles,
Expand Down Expand Up @@ -149,12 +148,14 @@ func gatherFilteredCerts(ctx context.Context, kubeClient kubernetes.Interface, a
errs = append(errs, err)
continue
}
if details == nil {
if len(details) == 0 {
continue
}
options.rewriteCertKeyPair(secret.ObjectMeta, details)
certs = append(certs, details)
for i := range details {
options.rewriteCertKeyPair(secret.ObjectMeta, details[i])
}

certs = append(certs, details...)
inClusterResourceData.CertKeyPairs = append(inClusterResourceData.CertKeyPairs,
certgraphapi.PKIRegistryInClusterCertKeyPair{
SecretLocation: certgraphapi.InClusterSecretLocation{
Expand Down
56 changes: 30 additions & 26 deletions pkg/certs/cert-inspection/certgraphanalysis/disk_certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (

"github.com/openshift/library-go/pkg/certs/cert-inspection/certgraphapi"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/cert"
)
Expand Down Expand Up @@ -185,18 +184,24 @@ func parseFileAsCertKeyPair(path string) ([]*certgraphapi.CertKeyPair, error) {
}
// Parse as kubeconfig
if kubeConfig, err := parseFileAsKubeConfig(path); err == nil {
if detail, err := GetCertKeyPairFromKubeConfig(kubeConfig, "", ""); err == nil {
fmt.Fprintf(os.Stdout, "Found a valid kubeconfig\n")
detail.Spec.OnDiskLocations = []certgraphapi.OnDiskCertKeyPairLocation{
{
Cert: certgraphapi.OnDiskLocation{
Path: path,
},
Key: certgraphapi.OnDiskLocation{
Path: path,
},
}}
details = append(details, detail)
details := []*certgraphapi.CertKeyPair{}
if rawConfig, err := kubeConfig.RawConfig(); err == nil {
for _, authInfo := range rawConfig.AuthInfos {
if certKeyPairs, err := GetCertKeyPairsFromKubeConfig(authInfo, nil); err == nil {
for i := range certKeyPairs {
certKeyPairs[i].Spec.OnDiskLocations = []certgraphapi.OnDiskCertKeyPairLocation{
{
Cert: certgraphapi.OnDiskLocation{
Path: path,
},
Key: certgraphapi.OnDiskLocation{
Path: path,
},
}}
}
details = append(details, certKeyPairs...)
}
}
return details, nil
}
}
Expand Down Expand Up @@ -226,15 +231,18 @@ func parseFileAsCA(path string) (*certgraphapi.CertificateAuthorityBundle, error
}
// Parse as kubeconfig
if kubeConfig, err := parseFileAsKubeConfig(path); err == nil {
fmt.Fprintf(os.Stdout, "Found a valid kubeconfig\n")
if detail, err := GetCAFromKubeConfig(kubeConfig, "", ""); err == nil {
detail.Spec.OnDiskLocations = []certgraphapi.OnDiskLocation{
{
Path: path,
},
if clientConfig, err := kubeConfig.ClientConfig(); err == nil {
fmt.Fprintf(os.Stdout, "Found a valid kubeconfig\n")
if detail, err := GetCAFromKubeConfig(clientConfig, "", ""); err == nil {
detail.Spec.OnDiskLocations = []certgraphapi.OnDiskLocation{
{
Path: path,
},
}
return detail, nil
}
return detail, nil
}

}
certificates, err := cert.ParseCertsPEM(bytes)
if err != nil {
Expand All @@ -259,16 +267,12 @@ func parseFileAsCA(path string) (*certgraphapi.CertificateAuthorityBundle, error
return detail, nil
}

func parseFileAsKubeConfig(path string) (*rest.Config, error) {
func parseFileAsKubeConfig(path string) (clientcmd.OverridingClientConfig, error) {
bytes, err := os.ReadFile(path)
if err != nil {
return nil, err
}
kubeConfig, err := clientcmd.NewClientConfigFromBytes(bytes)
if err != nil {
return nil, err
}
return kubeConfig.ClientConfig()
return clientcmd.NewClientConfigFromBytes(bytes)
}

func gatherCABundlesFromDisk(ctx context.Context, dir string, options certGenerationOptionList) ([]*certgraphapi.CertificateAuthorityBundle, []*certgraphapi.OnDiskLocationWithMetadata, error) {
Expand Down

0 comments on commit 40ee799

Please sign in to comment.