Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
e1320bba
Unverified
Commit
e1320bba
authored
Nov 01, 2018
by
Yago Nobre
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Validate kubeconfig files in case of external CA mode
parent
5fdad5c1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
220 additions
and
19 deletions
+220
-19
init.go
cmd/kubeadm/app/cmd/init.go
+11
-1
kubeconfig.go
cmd/kubeadm/app/cmd/phases/kubeconfig.go
+1
-2
kubeconfig.go
cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go
+60
-15
kubeconfig_test.go
cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go
+148
-1
No files found.
cmd/kubeadm/app/cmd/init.go
View file @
e1320bba
/*
Copyright 201
6
The Kubernetes Authors.
Copyright 201
8
The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
...
...
@@ -47,6 +47,7 @@ import (
clusterinfophase
"k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo"
nodebootstraptokenphase
"k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node"
certsphase
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
kubeconfigphase
"k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
kubeletphase
"k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet"
markmasterphase
"k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster"
patchnodephase
"k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode"
...
...
@@ -316,6 +317,15 @@ func newInitData(cmd *cobra.Command, options *initOptions, out io.Writer) (initD
// Checks if an external CA is provided by the user.
externalCA
,
_
:=
certsphase
.
UsingExternalCA
(
cfg
)
if
externalCA
{
kubeconfigDir
:=
kubeadmconstants
.
KubernetesDir
if
options
.
dryRun
{
kubeconfigDir
=
dryRunDir
}
if
err
:=
kubeconfigphase
.
ValidateKubeconfigsForExternalCA
(
kubeconfigDir
,
cfg
);
err
!=
nil
{
return
initData
{},
err
}
}
return
initData
{
cfg
:
cfg
,
...
...
cmd/kubeadm/app/cmd/phases/kubeconfig.go
View file @
e1320bba
/*
Copyright 201
7
The Kubernetes Authors.
Copyright 201
8
The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
...
...
@@ -116,7 +116,6 @@ func runKubeConfigFile(kubeConfigFileName string) func(workflow.RunData) error {
// if external CA mode, skip certificate authority generation
if
data
.
ExternalCA
()
{
//TODO: implement validation of existing kubeconfig files
fmt
.
Printf
(
"[kubeconfig] External CA mode: Using user provided %s
\n
"
,
kubeConfigFileName
)
return
nil
}
...
...
cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go
View file @
e1320bba
/*
Copyright 201
6
The Kubernetes Authors.
Copyright 201
8
The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
...
...
@@ -216,22 +216,12 @@ func buildKubeConfigFromSpec(spec *kubeConfigSpec, clustername string) (*clientc
),
nil
}
// createKubeConfigFileIfNotExists saves the KubeConfig object into a file if there isn't any file at the given path.
// If there already is a kubeconfig file at the given path; kubeadm tries to load it and check if the values in the
// existing and the expected config equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
// but if a file exists but has old content or isn't a kubeconfig file, this function returns an error.
func
createKubeConfigFileIfNotExists
(
outDir
,
filename
string
,
config
*
clientcmdapi
.
Config
)
error
{
// validateKubeConfig check if the kubeconfig file exist and has the expected CA and server URL
func
validateKubeConfig
(
outDir
,
filename
string
,
config
*
clientcmdapi
.
Config
)
error
{
kubeConfigFilePath
:=
filepath
.
Join
(
outDir
,
filename
)
// Check if the file exist, and if it doesn't, just write it to disk
if
_
,
err
:=
os
.
Stat
(
kubeConfigFilePath
);
os
.
IsNotExist
(
err
)
{
fmt
.
Printf
(
"[kubeconfig] Writing %q kubeconfig file
\n
"
,
filename
)
err
=
kubeconfigutil
.
WriteToDisk
(
kubeConfigFilePath
,
config
)
if
err
!=
nil
{
return
errors
.
Wrapf
(
err
,
"failed to save kubeconfig file %s on disk"
,
kubeConfigFilePath
)
}
return
nil
if
_
,
err
:=
os
.
Stat
(
kubeConfigFilePath
);
err
!=
nil
{
return
err
}
// The kubeconfig already exists, let's check if it has got the same CA and server URL
...
...
@@ -254,6 +244,29 @@ func createKubeConfigFileIfNotExists(outDir, filename string, config *clientcmda
return
errors
.
Errorf
(
"a kubeconfig file %q exists already but has got the wrong API Server URL"
,
kubeConfigFilePath
)
}
return
nil
}
// createKubeConfigFileIfNotExists saves the KubeConfig object into a file if there isn't any file at the given path.
// If there already is a kubeconfig file at the given path; kubeadm tries to load it and check if the values in the
// existing and the expected config equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
// but if a file exists but has old content or isn't a kubeconfig file, this function returns an error.
func
createKubeConfigFileIfNotExists
(
outDir
,
filename
string
,
config
*
clientcmdapi
.
Config
)
error
{
kubeConfigFilePath
:=
filepath
.
Join
(
outDir
,
filename
)
err
:=
validateKubeConfig
(
outDir
,
filename
,
config
)
if
err
!=
nil
{
// Check if the file exist, and if it doesn't, just write it to disk
if
!
os
.
IsNotExist
(
err
)
{
return
err
}
fmt
.
Printf
(
"[kubeconfig] Writing %q kubeconfig file
\n
"
,
filename
)
err
=
kubeconfigutil
.
WriteToDisk
(
kubeConfigFilePath
,
config
)
if
err
!=
nil
{
return
errors
.
Wrapf
(
err
,
"failed to save kubeconfig file %q on disk"
,
kubeConfigFilePath
)
}
return
nil
}
// kubeadm doesn't validate the existing kubeconfig file more than this (kubeadm trusts the client certs to be valid)
// Basically, if we find a kubeconfig file with the same path; the same CA cert and the same server URL;
// kubeadm thinks those files are equal and doesn't bother writing a new file
...
...
@@ -333,3 +346,35 @@ func writeKubeConfigFromSpec(out io.Writer, spec *kubeConfigSpec, clustername st
fmt
.
Fprintln
(
out
,
string
(
configBytes
))
return
nil
}
// ValidateKubeconfigsForExternalCA check if the kubeconfig file exist and has the expected CA and server URL using kubeadmapi.InitConfiguration.
func
ValidateKubeconfigsForExternalCA
(
outDir
string
,
cfg
*
kubeadmapi
.
InitConfiguration
)
error
{
kubeConfigFileNames
:=
[]
string
{
kubeadmconstants
.
AdminKubeConfigFileName
,
kubeadmconstants
.
KubeletKubeConfigFileName
,
kubeadmconstants
.
ControllerManagerKubeConfigFileName
,
kubeadmconstants
.
SchedulerKubeConfigFileName
,
}
specs
,
err
:=
getKubeConfigSpecs
(
cfg
)
if
err
!=
nil
{
return
err
}
for
_
,
kubeConfigFileName
:=
range
kubeConfigFileNames
{
spec
,
exists
:=
specs
[
kubeConfigFileName
]
if
!
exists
{
return
errors
.
Errorf
(
"couldn't retrive KubeConfigSpec for %s"
,
kubeConfigFileName
)
}
kubeconfig
,
err
:=
buildKubeConfigFromSpec
(
spec
,
cfg
.
ClusterName
)
if
err
!=
nil
{
return
err
}
if
err
=
validateKubeConfig
(
outDir
,
kubeConfigFileName
,
kubeconfig
);
err
!=
nil
{
return
err
}
}
return
nil
}
cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go
View file @
e1320bba
/*
Copyright 201
7
The Kubernetes Authors.
Copyright 201
8
The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
...
...
@@ -23,9 +23,12 @@ import (
"fmt"
"io"
"os"
"path/filepath"
"reflect"
"testing"
"github.com/renstrom/dedent"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi
"k8s.io/client-go/tools/clientcmd/api"
kubeadmapi
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
...
...
@@ -437,6 +440,150 @@ func TestWriteKubeConfig(t *testing.T) {
}
}
func
TestValidateKubeConfig
(
t
*
testing
.
T
)
{
caCert
,
caKey
:=
certstestutil
.
SetupCertificateAuthorithy
(
t
)
anotherCaCert
,
anotherCaKey
:=
certstestutil
.
SetupCertificateAuthorithy
(
t
)
config
:=
setupdKubeConfigWithClientAuth
(
t
,
caCert
,
caKey
,
"https://1.2.3.4:1234"
,
"test-cluster"
,
"myOrg1"
)
configWithAnotherClusterCa
:=
setupdKubeConfigWithClientAuth
(
t
,
anotherCaCert
,
anotherCaKey
,
"https://1.2.3.4:1234"
,
"test-cluster"
,
"myOrg1"
)
configWithAnotherServerURL
:=
setupdKubeConfigWithClientAuth
(
t
,
caCert
,
caKey
,
"https://4.3.2.1:4321"
,
"test-cluster"
,
"myOrg1"
)
tests
:=
map
[
string
]
struct
{
existingKubeConfig
*
clientcmdapi
.
Config
kubeConfig
*
clientcmdapi
.
Config
expectedError
bool
}{
"kubeconfig don't exist"
:
{
kubeConfig
:
config
,
expectedError
:
true
,
},
"kubeconfig exist and has invalid ca"
:
{
existingKubeConfig
:
configWithAnotherClusterCa
,
kubeConfig
:
config
,
expectedError
:
true
,
},
"kubeconfig exist and has invalid server url"
:
{
existingKubeConfig
:
configWithAnotherServerURL
,
kubeConfig
:
config
,
expectedError
:
true
,
},
"kubeconfig exist and is valid"
:
{
existingKubeConfig
:
config
,
kubeConfig
:
config
,
expectedError
:
false
,
},
}
for
name
,
test
:=
range
tests
{
tmpdir
:=
testutil
.
SetupTempDir
(
t
)
defer
os
.
RemoveAll
(
tmpdir
)
if
test
.
existingKubeConfig
!=
nil
{
if
err
:=
createKubeConfigFileIfNotExists
(
tmpdir
,
"test.conf"
,
test
.
existingKubeConfig
);
err
!=
nil
{
t
.
Errorf
(
"createKubeConfigFileIfNotExists failed"
)
}
}
err
:=
validateKubeConfig
(
tmpdir
,
"test.conf"
,
test
.
kubeConfig
)
if
(
err
!=
nil
)
!=
test
.
expectedError
{
t
.
Fatalf
(
dedent
.
Dedent
(
"validateKubeConfig failed
\n
%s
\n
expected error: %t
\n\t
got: %t
\n
error: %v"
),
name
,
test
.
expectedError
,
(
err
!=
nil
),
err
,
)
}
}
}
func
TestValidateKubeconfigsForExternalCA
(
t
*
testing
.
T
)
{
tmpDir
:=
testutil
.
SetupTempDir
(
t
)
defer
os
.
RemoveAll
(
tmpDir
)
pkiDir
:=
filepath
.
Join
(
tmpDir
,
"pki"
)
initConfig
:=
&
kubeadmapi
.
InitConfiguration
{
ClusterConfiguration
:
kubeadmapi
.
ClusterConfiguration
{
CertificatesDir
:
pkiDir
,
},
APIEndpoint
:
kubeadmapi
.
APIEndpoint
{
BindPort
:
1234
,
AdvertiseAddress
:
"1.2.3.4"
,
},
}
caCert
,
caKey
:=
certstestutil
.
SetupCertificateAuthorithy
(
t
)
anotherCaCert
,
anotherCaKey
:=
certstestutil
.
SetupCertificateAuthorithy
(
t
)
if
err
:=
pkiutil
.
WriteCertAndKey
(
pkiDir
,
kubeadmconstants
.
CACertAndKeyBaseName
,
caCert
,
caKey
);
err
!=
nil
{
t
.
Fatalf
(
"failure while saving CA certificate and key: %v"
,
err
)
}
config
:=
setupdKubeConfigWithClientAuth
(
t
,
caCert
,
caKey
,
"https://1.2.3.4:1234"
,
"test-cluster"
,
"myOrg1"
)
configWithAnotherClusterCa
:=
setupdKubeConfigWithClientAuth
(
t
,
anotherCaCert
,
anotherCaKey
,
"https://1.2.3.4:1234"
,
"test-cluster"
,
"myOrg1"
)
configWithAnotherServerURL
:=
setupdKubeConfigWithClientAuth
(
t
,
caCert
,
caKey
,
"https://4.3.2.1:4321"
,
"test-cluster"
,
"myOrg1"
)
tests
:=
map
[
string
]
struct
{
filesToWrite
map
[
string
]
*
clientcmdapi
.
Config
initConfig
*
kubeadmapi
.
InitConfiguration
expectedError
bool
}{
"files don't exist"
:
{
initConfig
:
initConfig
,
expectedError
:
true
,
},
"some files don't exist"
:
{
filesToWrite
:
map
[
string
]
*
clientcmdapi
.
Config
{
kubeadmconstants
.
AdminKubeConfigFileName
:
config
,
kubeadmconstants
.
KubeletKubeConfigFileName
:
config
,
},
initConfig
:
initConfig
,
expectedError
:
true
,
},
"some files are invalid"
:
{
filesToWrite
:
map
[
string
]
*
clientcmdapi
.
Config
{
kubeadmconstants
.
AdminKubeConfigFileName
:
config
,
kubeadmconstants
.
KubeletKubeConfigFileName
:
config
,
kubeadmconstants
.
ControllerManagerKubeConfigFileName
:
configWithAnotherClusterCa
,
kubeadmconstants
.
SchedulerKubeConfigFileName
:
configWithAnotherServerURL
,
},
initConfig
:
initConfig
,
expectedError
:
true
,
},
"all files are valid"
:
{
filesToWrite
:
map
[
string
]
*
clientcmdapi
.
Config
{
kubeadmconstants
.
AdminKubeConfigFileName
:
config
,
kubeadmconstants
.
KubeletKubeConfigFileName
:
config
,
kubeadmconstants
.
ControllerManagerKubeConfigFileName
:
config
,
kubeadmconstants
.
SchedulerKubeConfigFileName
:
config
,
},
initConfig
:
initConfig
,
expectedError
:
false
,
},
}
for
name
,
test
:=
range
tests
{
tmpdir
:=
testutil
.
SetupTempDir
(
t
)
defer
os
.
RemoveAll
(
tmpdir
)
for
name
,
config
:=
range
test
.
filesToWrite
{
if
err
:=
createKubeConfigFileIfNotExists
(
tmpdir
,
name
,
config
);
err
!=
nil
{
t
.
Errorf
(
"createKubeConfigFileIfNotExists failed"
)
}
}
err
:=
ValidateKubeconfigsForExternalCA
(
tmpdir
,
test
.
initConfig
)
if
(
err
!=
nil
)
!=
test
.
expectedError
{
t
.
Fatalf
(
dedent
.
Dedent
(
"ValidateKubeconfigsForExternalCA failed
\n
%s
\n
expected error: %t
\n\t
got: %t
\n
error: %v"
),
name
,
test
.
expectedError
,
(
err
!=
nil
),
err
,
)
}
}
}
// setupdKubeConfigWithClientAuth is a test utility function that wraps buildKubeConfigFromSpec for building a KubeConfig object With ClientAuth
func
setupdKubeConfigWithClientAuth
(
t
*
testing
.
T
,
caCert
*
x509
.
Certificate
,
caKey
*
rsa
.
PrivateKey
,
APIServer
,
clientName
,
clustername
string
,
organizations
...
string
)
*
clientcmdapi
.
Config
{
spec
:=
&
kubeConfigSpec
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment