compute: parse raw kubeconfig data into resource credentials secret keys format

Signed-off-by: Jared Watts <jbw976@gmail.com>
This commit is contained in:
Jared Watts 2018-12-02 19:37:28 -08:00
parent 3012c705e7
commit e1cd0967d5
3 changed files with 173 additions and 2 deletions

View File

@ -0,0 +1,99 @@
/*
Copyright 2018 The Crossplane Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
"fmt"
corev1alpha1 "github.com/crossplaneio/crossplane/pkg/apis/core/v1alpha1"
"github.com/ghodss/yaml"
kubectlv1 "k8s.io/client-go/tools/clientcmd/api/v1"
)
func ParseKubeconfig(rawKubeconfig []byte) (map[string][]byte, error) {
// unmarshal the raw kubeconfig into a strongly typed kubeconfig struct
kubeconfig := &kubectlv1.Config{}
if err := yaml.Unmarshal(rawKubeconfig, kubeconfig); err != nil {
return nil, fmt.Errorf("failed to unmarshal kubeconfig: %+v", err)
}
if len(kubeconfig.Contexts) == 0 {
// no contexts in the kubeconfig, we can't return anything meaningful
return nil, fmt.Errorf("no contexts found in kubeconfig")
}
// find the current context for this kubeconfig
var currentContext *kubectlv1.NamedContext
if kubeconfig.CurrentContext == "" {
// no current context set, just use the first context
currentContext = &kubeconfig.Contexts[0]
} else {
// current context is set, find the matching named context
for i, ctx := range kubeconfig.Contexts {
if kubeconfig.CurrentContext == ctx.Name {
currentContext = &kubeconfig.Contexts[i]
break
}
}
}
if currentContext == nil {
// failed to find a current context
return nil, fmt.Errorf("failed to find current context in kubeconfig")
}
// find the cluster for the current context
var cluster *kubectlv1.NamedCluster
for i, c := range kubeconfig.Clusters {
if currentContext.Context.Cluster == c.Name {
cluster = &kubeconfig.Clusters[i]
break
}
}
if cluster == nil {
// failed to find the current context's cluster
return nil, fmt.Errorf("failed to find cluster %s in kubeconfig", currentContext.Context.Cluster)
}
// find the auth info for the current context
var authInfo *kubectlv1.NamedAuthInfo
for i, ai := range kubeconfig.AuthInfos {
if currentContext.Context.AuthInfo == ai.Name {
authInfo = &kubeconfig.AuthInfos[i]
break
}
}
if authInfo == nil {
// failed to find the current context's auth info
return nil, fmt.Errorf("failed to find auth info %s in kubeconfig", currentContext.Context.AuthInfo)
}
// we have a context, a cluster, and an auth info. let's fill out the cluster resource map
kubeconfigData := map[string][]byte{
corev1alpha1.ResourceCredentialsSecretEndpointKey: []byte(cluster.Cluster.Server),
corev1alpha1.ResourceCredentialsSecretUserKey: []byte(authInfo.AuthInfo.Username),
corev1alpha1.ResourceCredentialsSecretPasswordKey: []byte(authInfo.AuthInfo.Password),
corev1alpha1.ResourceCredentialsSecretCAKey: cluster.Cluster.CertificateAuthorityData,
corev1alpha1.ResourceCredentialsSecretClientCertKey: authInfo.AuthInfo.ClientCertificateData,
corev1alpha1.ResourceCredentialsSecretClientKeyKey: authInfo.AuthInfo.ClientKeyData,
corev1alpha1.ResourceCredentialsTokenKey: []byte(authInfo.AuthInfo.Token),
}
return kubeconfigData, nil
}

View File

@ -0,0 +1,72 @@
/*
Copyright 2018 The Crossplane Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
"testing"
corev1alpha1 "github.com/crossplaneio/crossplane/pkg/apis/core/v1alpha1"
"github.com/onsi/gomega"
)
const (
// This data format is the general kubectl config (kubeconfig) format, but it specifically
// came from the Azure AKS ListClusterAdminCredentials API:
// https://docs.microsoft.com/en-us/rest/api/aks/managedclusters/listclusteradmincredentials
// The values in it have all been replaced with fake data
mockRawClusterCredentialsData = `apiVersion: v1
clusters:
- cluster:
certificate-authority-data: Y2VydGlmaWNhdGUtYXV0aG9yaXR5LWRhdGEtdmFsdWU=
server: https://crossplane-aks-55e038af.hcp.westus2.azmk8s.io:443
name: aks-c7f893e4-d903-402c-ba60-8be6bbeac6a3
contexts:
- context:
cluster: aks-c7f893e4-d903-402c-ba60-8be6bbeac6a3
user: clusterAdmin_rg-123_aks-c7f893e4-d903-402c-ba60-8be6bbeac6a3
namespace: foo
name: aks-c7f893e4-d903-402c-ba60-8be6bbeac6a3
current-context: aks-c7f893e4-d903-402c-ba60-8be6bbeac6a3
kind: Config
preferences: {}
users:
- name: clusterAdmin_rg-123_aks-c7f893e4-d903-402c-ba60-8be6bbeac6a3
user:
client-certificate-data: Y2xpZW50LWNlcnRpZmljYXRlLWRhdGEtdmFsdWU=
client-key-data: Y2xpZW50LWtleS1kYXRhLXZhbHVl
token: 799e6a56219da5ff09e3b41b1dd08f3f
`
)
func TestParseKubeconfig(t *testing.T) {
g := gomega.NewGomegaWithT(t)
// the unmarshal of the raw data will decode the base64 encoded values, so we expect them in plain-text
expectedKubeconfigData := map[string][]byte{
corev1alpha1.ResourceCredentialsSecretEndpointKey: []byte("https://crossplane-aks-55e038af.hcp.westus2.azmk8s.io:443"),
corev1alpha1.ResourceCredentialsSecretUserKey: []byte(""),
corev1alpha1.ResourceCredentialsSecretPasswordKey: []byte(""),
corev1alpha1.ResourceCredentialsSecretCAKey: []byte("certificate-authority-data-value"),
corev1alpha1.ResourceCredentialsSecretClientCertKey: []byte("client-certificate-data-value"),
corev1alpha1.ResourceCredentialsSecretClientKeyKey: []byte("client-key-data-value"),
corev1alpha1.ResourceCredentialsTokenKey: []byte("799e6a56219da5ff09e3b41b1dd08f3f"),
}
kubeconfigData, err := ParseKubeconfig([]byte(mockRawClusterCredentialsData))
g.Expect(err).NotTo(gomega.HaveOccurred())
g.Expect(kubeconfigData).To(gomega.Equal(expectedKubeconfigData))
}

View File

@ -31,10 +31,10 @@ const (
ResourceCredentialsSecretClientCertKey = "clientCert"
// ResourceCredentialsSecretClientKeyKey is the key inside a connection secret for the client key
ResourceCredentialsSecretClientKeyKey = "clientKey"
// ResourceCredentialsSecretClusterConfigFile is the key inside a connection secret for the full cluster configuration file
ResourceCredentialsSecretClusterConfigFile = "clusterConfig"
// ResourceCredentialsTokenKey is the key inside a connection secret for the bearer token value
ResourceCredentialsTokenKey = "token"
// ResourceCredentialsSecretKubeconfigFileKey is the key inside a connection secret for the full kubeconfig file
ResourceCredentialsSecretKubeconfigFileKey = "kubeconfig"
)
// Resource defines operations supported by managed resource