Merge "Encoding secret data in airshipctl config files"
This commit is contained in:
commit
93025dfadd
@ -60,7 +60,10 @@ func NewGetAuthInfoCommand(rootSettings *environment.AirshipCTLSettings) *cobra.
|
||||
}
|
||||
fmt.Fprintln(cmd.OutOrStdout(), authinfo)
|
||||
} else {
|
||||
authinfos := airconfig.GetAuthInfos()
|
||||
authinfos, err := airconfig.GetAuthInfos()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(authinfos) == 0 {
|
||||
fmt.Fprintln(cmd.OutOrStdout(), "No User credentials found in the configuration.")
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
kubeconfig "k8s.io/client-go/tools/clientcmd/api"
|
||||
|
||||
cmd "opendev.org/airship/airshipctl/cmd/config"
|
||||
@ -39,9 +41,15 @@ func TestGetAuthInfoCmd(t *testing.T) {
|
||||
settings := &environment.AirshipCTLSettings{
|
||||
Config: &config.Config{
|
||||
AuthInfos: map[string]*config.AuthInfo{
|
||||
fooAuthInfo: getTestAuthInfo(),
|
||||
barAuthInfo: getTestAuthInfo(),
|
||||
bazAuthInfo: getTestAuthInfo(),
|
||||
fooAuthInfo: getTestAuthInfo(fooAuthInfo),
|
||||
},
|
||||
},
|
||||
}
|
||||
settingsWithMultipleAuth := &environment.AirshipCTLSettings{
|
||||
Config: &config.Config{
|
||||
AuthInfos: map[string]*config.AuthInfo{
|
||||
barAuthInfo: getTestAuthInfo(barAuthInfo),
|
||||
bazAuthInfo: getTestAuthInfo(bazAuthInfo),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -53,8 +61,9 @@ func TestGetAuthInfoCmd(t *testing.T) {
|
||||
Cmd: cmd.NewGetAuthInfoCommand(settings),
|
||||
},
|
||||
{
|
||||
Name: "get-all-credentials",
|
||||
Cmd: cmd.NewGetAuthInfoCommand(settings),
|
||||
Name: "get-all-credentials",
|
||||
CmdLine: "",
|
||||
Cmd: cmd.NewGetAuthInfoCommand(settingsWithMultipleAuth),
|
||||
},
|
||||
{
|
||||
Name: "missing",
|
||||
@ -80,17 +89,31 @@ func TestNoAuthInfosGetAuthInfoCmd(t *testing.T) {
|
||||
testutil.RunTest(t, cmdTest)
|
||||
}
|
||||
|
||||
func getTestAuthInfo() *config.AuthInfo {
|
||||
func TestDecodeAuthInfo(t *testing.T) {
|
||||
_, err := config.DecodeAuthInfo(&kubeconfig.AuthInfo{Password: "dummy_password"})
|
||||
assert.Error(t, err, config.ErrDecodingCredentials{Given: "dummy_password"})
|
||||
|
||||
_, err = config.DecodeAuthInfo(&kubeconfig.AuthInfo{ClientCertificate: "dummy_certificate"})
|
||||
assert.Error(t, err, config.ErrDecodingCredentials{Given: "dummy_certificate"})
|
||||
|
||||
_, err = config.DecodeAuthInfo(&kubeconfig.AuthInfo{ClientKey: "dummy_key"})
|
||||
assert.Error(t, err, config.ErrDecodingCredentials{Given: "dummy_key"})
|
||||
|
||||
_, err = config.DecodeAuthInfo(&kubeconfig.AuthInfo{Token: "dummy_token"})
|
||||
assert.Error(t, err, config.ErrDecodingCredentials{Given: "dummy_token"})
|
||||
}
|
||||
|
||||
func getTestAuthInfo(authName string) *config.AuthInfo {
|
||||
kAuthInfo := &kubeconfig.AuthInfo{
|
||||
Username: "dummy_user",
|
||||
Password: "dummy_password",
|
||||
ClientCertificate: "dummy_certificate",
|
||||
ClientKey: "dummy_key",
|
||||
Token: "dummy_token",
|
||||
Username: authName + "_user",
|
||||
Password: authName + "_password",
|
||||
ClientCertificate: authName + "_certificate",
|
||||
ClientKey: authName + "_key",
|
||||
Token: authName + "_token",
|
||||
}
|
||||
|
||||
newAuthInfo := &config.AuthInfo{}
|
||||
newAuthInfo.SetKubeAuthInfo(kAuthInfo)
|
||||
|
||||
encodedKAuthInfo := config.EncodeAuthInfo(kAuthInfo)
|
||||
newAuthInfo.SetKubeAuthInfo(encodedKAuthInfo)
|
||||
return newAuthInfo
|
||||
}
|
||||
|
@ -81,8 +81,9 @@ func initInputConfig(t *testing.T) (given *config.Config, cleanup func(*testing.
|
||||
kubeAuthInfo := kubeconfig.NewAuthInfo()
|
||||
kubeAuthInfo.Username = testUsername
|
||||
kubeAuthInfo.Password = testPassword
|
||||
given.KubeConfig().AuthInfos[existingUserName] = kubeAuthInfo
|
||||
given.AuthInfos[existingUserName].SetKubeAuthInfo(kubeAuthInfo)
|
||||
encodedKAuthInfo := config.EncodeAuthInfo(kubeAuthInfo)
|
||||
given.KubeConfig().AuthInfos[existingUserName] = encodedKAuthInfo
|
||||
given.AuthInfos[existingUserName].SetKubeAuthInfo(encodedKAuthInfo)
|
||||
|
||||
return given, givenCleanup
|
||||
}
|
||||
|
@ -1,21 +1,14 @@
|
||||
LocationOfOrigin: ""
|
||||
client-certificate: dummy_certificate
|
||||
client-key: dummy_key
|
||||
password: dummy_password
|
||||
token: dummy_token
|
||||
username: dummy_user
|
||||
client-certificate: AuthInfoBar_certificate
|
||||
client-key: AuthInfoBar_key
|
||||
password: AuthInfoBar_password
|
||||
token: AuthInfoBar_token
|
||||
username: AuthInfoBar_user
|
||||
|
||||
LocationOfOrigin: ""
|
||||
client-certificate: dummy_certificate
|
||||
client-key: dummy_key
|
||||
password: dummy_password
|
||||
token: dummy_token
|
||||
username: dummy_user
|
||||
|
||||
LocationOfOrigin: ""
|
||||
client-certificate: dummy_certificate
|
||||
client-key: dummy_key
|
||||
password: dummy_password
|
||||
token: dummy_token
|
||||
username: dummy_user
|
||||
client-certificate: AuthInfoBaz_certificate
|
||||
client-key: AuthInfoBaz_key
|
||||
password: AuthInfoBaz_password
|
||||
token: AuthInfoBaz_token
|
||||
username: AuthInfoBaz_user
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
LocationOfOrigin: ""
|
||||
client-certificate: dummy_certificate
|
||||
client-key: dummy_key
|
||||
password: dummy_password
|
||||
token: dummy_token
|
||||
username: dummy_user
|
||||
client-certificate: AuthInfoFoo_certificate
|
||||
client-key: AuthInfoFoo_key
|
||||
password: AuthInfoFoo_password
|
||||
token: AuthInfoFoo_token
|
||||
username: AuthInfoFoo_user
|
||||
|
||||
|
@ -29,7 +29,8 @@ func TestGetAuthInfos(t *testing.T) {
|
||||
conf, cleanup := testutil.InitConfig(t)
|
||||
defer cleanup(t)
|
||||
|
||||
authinfos := conf.GetAuthInfos()
|
||||
authinfos, err := conf.GetAuthInfos()
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, authinfos, 3)
|
||||
}
|
||||
|
||||
@ -65,15 +66,17 @@ func TestModifyAuthInfo(t *testing.T) {
|
||||
authinfo := conf.AddAuthInfo(co)
|
||||
|
||||
co.Username += stringDelta
|
||||
co.Password += stringDelta
|
||||
co.ClientCertificate += stringDelta
|
||||
co.ClientKey += stringDelta
|
||||
co.Token += stringDelta
|
||||
co.Password = newPassword
|
||||
co.ClientCertificate = newCertificate
|
||||
co.ClientKey = newKey
|
||||
co.Token = newToken
|
||||
conf.ModifyAuthInfo(authinfo, co)
|
||||
assert.EqualValues(t, conf.AuthInfos[co.Name].KubeAuthInfo().Username, co.Username)
|
||||
assert.EqualValues(t, conf.AuthInfos[co.Name].KubeAuthInfo().Password, co.Password)
|
||||
assert.EqualValues(t, conf.AuthInfos[co.Name].KubeAuthInfo().ClientCertificate, co.ClientCertificate)
|
||||
assert.EqualValues(t, conf.AuthInfos[co.Name].KubeAuthInfo().ClientKey, co.ClientKey)
|
||||
assert.EqualValues(t, conf.AuthInfos[co.Name].KubeAuthInfo().Token, co.Token)
|
||||
assert.EqualValues(t, conf.AuthInfos[co.Name], authinfo)
|
||||
modifiedAuthinfo, err := conf.GetAuthInfo(co.Name)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, modifiedAuthinfo.KubeAuthInfo().Username, co.Username)
|
||||
assert.EqualValues(t, modifiedAuthinfo.KubeAuthInfo().Password, co.Password)
|
||||
assert.EqualValues(t, modifiedAuthinfo.KubeAuthInfo().ClientCertificate, co.ClientCertificate)
|
||||
assert.EqualValues(t, modifiedAuthinfo.KubeAuthInfo().ClientKey, co.ClientKey)
|
||||
assert.EqualValues(t, modifiedAuthinfo.KubeAuthInfo().Token, co.Token)
|
||||
assert.EqualValues(t, modifiedAuthinfo, authinfo)
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ func (c *Config) reconcileAuthInfos() {
|
||||
// Add the reference
|
||||
c.AuthInfos[key] = NewAuthInfo()
|
||||
}
|
||||
c.AuthInfos[key].SetKubeAuthInfo(authinfo)
|
||||
c.AuthInfos[key].authInfo = authinfo
|
||||
}
|
||||
// Checking if there is any AuthInfo reference in airship config that does not match
|
||||
// an actual Auth Info struct in kubeconfig
|
||||
@ -711,12 +711,17 @@ func (c *Config) GetAuthInfo(aiName string) (*AuthInfo, error) {
|
||||
if !exists {
|
||||
return nil, ErrMissingConfig{What: fmt.Sprintf("User credentials with name '%s'", aiName)}
|
||||
}
|
||||
decodedAuthInfo, err := DecodeAuthInfo(authinfo.authInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authinfo.authInfo = decodedAuthInfo
|
||||
return authinfo, nil
|
||||
}
|
||||
|
||||
// GetAuthInfos returns a slice containing all the AuthInfos associated with
|
||||
// the Config sorted by name
|
||||
func (c *Config) GetAuthInfos() []*AuthInfo {
|
||||
func (c *Config) GetAuthInfos() ([]*AuthInfo, error) {
|
||||
keys := make([]string, 0, len(c.AuthInfos))
|
||||
for name := range c.AuthInfos {
|
||||
keys = append(keys, name)
|
||||
@ -725,9 +730,14 @@ func (c *Config) GetAuthInfos() []*AuthInfo {
|
||||
|
||||
authInfos := make([]*AuthInfo, 0, len(c.AuthInfos))
|
||||
for _, name := range keys {
|
||||
decodedAuthInfo, err := DecodeAuthInfo(c.AuthInfos[name].authInfo)
|
||||
if err != nil {
|
||||
return []*AuthInfo{}, err
|
||||
}
|
||||
c.AuthInfos[name].authInfo = decodedAuthInfo
|
||||
authInfos = append(authInfos, c.AuthInfos[name])
|
||||
}
|
||||
return authInfos
|
||||
return authInfos, nil
|
||||
}
|
||||
|
||||
// AddAuthInfo creates new AuthInfo with context details updated
|
||||
@ -738,7 +748,7 @@ func (c *Config) AddAuthInfo(theAuthInfo *AuthInfoOptions) *AuthInfo {
|
||||
c.AuthInfos[theAuthInfo.Name] = nAuthInfo
|
||||
// Create a new KubeConfig AuthInfo object as well
|
||||
authInfo := clientcmdapi.NewAuthInfo()
|
||||
nAuthInfo.SetKubeAuthInfo(authInfo)
|
||||
nAuthInfo.authInfo = authInfo
|
||||
c.KubeConfig().AuthInfos[theAuthInfo.Name] = authInfo
|
||||
|
||||
c.ModifyAuthInfo(nAuthInfo, theAuthInfo)
|
||||
@ -747,24 +757,24 @@ func (c *Config) AddAuthInfo(theAuthInfo *AuthInfoOptions) *AuthInfo {
|
||||
|
||||
// ModifyAuthInfo updates the AuthInfo in the Config object
|
||||
func (c *Config) ModifyAuthInfo(authinfo *AuthInfo, theAuthInfo *AuthInfoOptions) {
|
||||
kubeAuthInfo := authinfo.KubeAuthInfo()
|
||||
kubeAuthInfo := EncodeAuthInfo(authinfo.KubeAuthInfo())
|
||||
if kubeAuthInfo == nil {
|
||||
return
|
||||
}
|
||||
if theAuthInfo.ClientCertificate != "" {
|
||||
kubeAuthInfo.ClientCertificate = theAuthInfo.ClientCertificate
|
||||
kubeAuthInfo.ClientCertificate = EncodeString(theAuthInfo.ClientCertificate)
|
||||
}
|
||||
if theAuthInfo.Token != "" {
|
||||
kubeAuthInfo.Token = theAuthInfo.Token
|
||||
kubeAuthInfo.Token = EncodeString(theAuthInfo.Token)
|
||||
}
|
||||
if theAuthInfo.Username != "" {
|
||||
kubeAuthInfo.Username = theAuthInfo.Username
|
||||
}
|
||||
if theAuthInfo.Password != "" {
|
||||
kubeAuthInfo.Password = theAuthInfo.Password
|
||||
kubeAuthInfo.Password = EncodeString(theAuthInfo.Password)
|
||||
}
|
||||
if theAuthInfo.ClientKey != "" {
|
||||
kubeAuthInfo.ClientKey = theAuthInfo.ClientKey
|
||||
kubeAuthInfo.ClientKey = EncodeString(theAuthInfo.ClientKey)
|
||||
}
|
||||
}
|
||||
|
||||
@ -909,3 +919,44 @@ func (m *ManagementConfiguration) String() string {
|
||||
}
|
||||
return string(yamlData)
|
||||
}
|
||||
|
||||
// DecodeAuthInfo returns authInfo with credentials decoded
|
||||
func DecodeAuthInfo(authinfo *clientcmdapi.AuthInfo) (*clientcmdapi.AuthInfo, error) {
|
||||
password := authinfo.Password
|
||||
decodedPassword, err := DecodeString(password)
|
||||
if err != nil {
|
||||
return nil, ErrDecodingCredentials{Given: password}
|
||||
}
|
||||
authinfo.Password = decodedPassword
|
||||
|
||||
token := authinfo.Token
|
||||
decodedToken, err := DecodeString(token)
|
||||
if err != nil {
|
||||
return nil, ErrDecodingCredentials{Given: token}
|
||||
}
|
||||
authinfo.Token = decodedToken
|
||||
|
||||
clientCert := authinfo.ClientCertificate
|
||||
decodedClientCertificate, err := DecodeString(clientCert)
|
||||
if err != nil {
|
||||
return nil, ErrDecodingCredentials{Given: clientCert}
|
||||
}
|
||||
authinfo.ClientCertificate = decodedClientCertificate
|
||||
|
||||
clientKey := authinfo.ClientKey
|
||||
decodedClientKey, err := DecodeString(clientKey)
|
||||
if err != nil {
|
||||
return nil, ErrDecodingCredentials{Given: clientKey}
|
||||
}
|
||||
authinfo.ClientKey = decodedClientKey
|
||||
return authinfo, nil
|
||||
}
|
||||
|
||||
// EncodeAuthInfo returns authInfo with credentials base64 encoded
|
||||
func EncodeAuthInfo(authinfo *clientcmdapi.AuthInfo) *clientcmdapi.AuthInfo {
|
||||
authinfo.Password = EncodeString(authinfo.Password)
|
||||
authinfo.Token = EncodeString(authinfo.Token)
|
||||
authinfo.ClientCertificate = EncodeString(authinfo.ClientCertificate)
|
||||
authinfo.ClientKey = EncodeString(authinfo.ClientKey)
|
||||
return authinfo
|
||||
}
|
||||
|
@ -34,6 +34,10 @@ const (
|
||||
stringDelta = "_changed"
|
||||
currentContextName = "def_ephemeral"
|
||||
defaultString = "default"
|
||||
newToken = "dummy_token_changed"
|
||||
newPassword = "dummy_password_changed"
|
||||
newCertificate = "dummy_certificate_changed"
|
||||
newKey = "dummy_key_changed"
|
||||
)
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
|
@ -169,3 +169,12 @@ type ErrEmptyContextName struct {
|
||||
func (e ErrEmptyContextName) Error() string {
|
||||
return "Context name must not be empty."
|
||||
}
|
||||
|
||||
// ErrDecodingCredentials returned when the given string cannot be decoded
|
||||
type ErrDecodingCredentials struct {
|
||||
Given string
|
||||
}
|
||||
|
||||
func (e ErrDecodingCredentials) Error() string {
|
||||
return fmt.Sprintf("Error decoding credentials. String '%s' cannot not be decoded", e.Given)
|
||||
}
|
||||
|
8
pkg/config/testdata/authinfo-string.yaml
vendored
8
pkg/config/testdata/authinfo-string.yaml
vendored
@ -1,6 +1,6 @@
|
||||
LocationOfOrigin: ""
|
||||
client-certificate: dummy_certificate
|
||||
client-key: dummy_key
|
||||
password: dummy_password
|
||||
token: dummy_token
|
||||
client-certificate: ZHVtbXlfY2VydGlmaWNhdGU=
|
||||
client-key: ZHVtbXlfa2V5
|
||||
password: ZHVtbXlfcGFzc3dvcmQ=
|
||||
token: ZHVtbXlfdG9rZW4=
|
||||
username: dummy_username
|
||||
|
@ -17,6 +17,8 @@ limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/remote/redfish"
|
||||
)
|
||||
|
||||
@ -109,3 +111,18 @@ func NewRepository() *Repository {
|
||||
func NewAuthInfo() *AuthInfo {
|
||||
return &AuthInfo{}
|
||||
}
|
||||
|
||||
// EncodeString returns the base64 encoding of given string
|
||||
func EncodeString(given string) string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(given))
|
||||
}
|
||||
|
||||
// DecodeString returns the base64 decoded string
|
||||
// If err decoding, return the given string
|
||||
func DecodeString(given string) (string, error) {
|
||||
decoded, err := base64.StdEncoding.DecodeString(given)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(decoded), nil
|
||||
}
|
||||
|
@ -145,7 +145,8 @@ func DummyAuthInfo() *config.AuthInfo {
|
||||
authinfo.ClientCertificate = "dummy_certificate"
|
||||
authinfo.ClientKey = "dummy_key"
|
||||
authinfo.Token = "dummy_token"
|
||||
a.SetKubeAuthInfo(authinfo)
|
||||
encodedAuthInfo := config.EncodeAuthInfo(authinfo)
|
||||
a.SetKubeAuthInfo(encodedAuthInfo)
|
||||
return a
|
||||
}
|
||||
|
||||
@ -356,7 +357,7 @@ users:
|
||||
- name: def-user
|
||||
user:
|
||||
username: dummy_username
|
||||
password: dummy_password
|
||||
password: ZHVtbXlfcGFzc3dvcmQK
|
||||
- name: k-admin
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJQXhEdzk2RUY4SXN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T1RBNU1qa3hOekF6TURsYUZ3MHlNREE1TWpneE56QXpNVEphTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXV6R0pZdlBaNkRvaTQyMUQKSzhXSmFaQ25OQWQycXo1cC8wNDJvRnpRUGJyQWd6RTJxWVZrek9MOHhBVmVSN1NONXdXb1RXRXlGOEVWN3JyLwo0K0hoSEdpcTVQbXF1SUZ5enpuNi9JWmM4alU5eEVmenZpa2NpckxmVTR2UlhKUXdWd2dBU05sMkFXQUloMmRECmRUcmpCQ2ZpS1dNSHlqMFJiSGFsc0J6T3BnVC9IVHYzR1F6blVRekZLdjJkajVWMU5rUy9ESGp5UlJKK0VMNlEKQlltR3NlZzVQNE5iQzllYnVpcG1NVEFxL0p1bU9vb2QrRmpMMm5acUw2Zkk2ZkJ0RjVPR2xwQ0IxWUo4ZnpDdApHUVFaN0hUSWJkYjJ0cDQzRlZPaHlRYlZjSHFUQTA0UEoxNSswV0F5bVVKVXo4WEE1NDRyL2J2NzRKY0pVUkZoCmFyWmlRd0lEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMMmhIUmVibEl2VHJTMFNmUVg1RG9ueVVhNy84aTg1endVWApSd3dqdzFuS0U0NDJKbWZWRGZ5b0hRYUM4Ti9MQkxyUXM0U0lqU1JYdmFHU1dSQnRnT1RRV21Db1laMXdSbjdwCndDTXZQTERJdHNWWm90SEZpUFl2b1lHWFFUSXA3YlROMmg1OEJaaEZ3d25nWUovT04zeG1rd29IN1IxYmVxWEYKWHF1TTluekhESk41VlZub1lQR09yRHMwWlg1RnNxNGtWVU0wVExNQm9qN1ZIRDhmU0E5RjRYNU4yMldsZnNPMAo4aksrRFJDWTAyaHBrYTZQQ0pQS0lNOEJaMUFSMG9ZakZxT0plcXpPTjBqcnpYWHh4S2pHVFVUb1BldVA5dCtCCjJOMVA1TnI4a2oxM0lrend5Q1NZclFVN09ZM3ltZmJobHkrcXZxaFVFa014MlQ1SkpmQT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
|
Loading…
Reference in New Issue
Block a user