Merge pull request #10264 from mikedanese/ca-token

add ca cert to token controller and all service accounts
This commit is contained in:
Maxwell Forbes 2015-06-25 09:56:35 -07:00
commit 655179dcfb
11 changed files with 69 additions and 23 deletions

View File

@ -28,7 +28,13 @@
{% endif -%}
{% endif -%}
{% set params = "--master=127.0.0.1:8080" + " " + cluster_name + " " + cluster_cidr + " " + allocate_node_cidrs + " " + cloud_provider + " " + cloud_config + service_account_key + pillar['log_level'] -%}
{% set root_ca_file = "" -%}
{% if grains['cloud'] is defined and grains.cloud in [ 'aws', 'gce' ] %}
{% set root_ca_file = "--root_ca_file=/srv/kubernetes/ca.crt" -%}
{% endif -%}
{% set params = "--master=127.0.0.1:8080" + " " + cluster_name + " " + cluster_cidr + " " + allocate_node_cidrs + " " + cloud_provider + " " + cloud_config + service_account_key + pillar['log_level'] + " " + root_ca_file -%}
{
"apiVersion": "v1beta3",

View File

@ -23,6 +23,8 @@ limitations under the License.
package app
import (
"fmt"
"io/ioutil"
"net"
"net/http"
"net/http/pprof"
@ -73,6 +75,7 @@ type CMServer struct {
DeletingPodsQps float32
DeletingPodsBurst int
ServiceAccountKeyFile string
RootCAFile string
ClusterName string
ClusterCIDR util.IPNet
@ -156,6 +159,7 @@ func (s *CMServer) AddFlags(fs *pflag.FlagSet) {
fs.BoolVar(&s.AllocateNodeCIDRs, "allocate-node-cidrs", false, "Should CIDRs for Pods be allocated and set on the cloud provider.")
fs.StringVar(&s.Master, "master", s.Master, "The address of the Kubernetes API server (overrides any value in kubeconfig)")
fs.StringVar(&s.Kubeconfig, "kubeconfig", s.Kubeconfig, "Path to kubeconfig file with authorization and master location information.")
fs.StringVar(&s.RootCAFile, "root-ca-file", s.RootCAFile, "If set, this root certificate authority will be included in service account's token secret. This must be a valid PEM-encoded CA bundle.")
}
// Run runs the CMServer. This should never exit.
@ -243,6 +247,20 @@ func (s *CMServer) Run(_ []string) error {
}
pvRecycler.Run()
var rootCA []byte
if s.RootCAFile != "" {
rootCA, err := ioutil.ReadFile(s.RootCAFile)
if err != nil {
return fmt.Errorf("error reading root-ca-file at %s: %v", s.RootCAFile, err)
}
if _, err := util.CertsFromPEM(rootCA); err != nil {
return fmt.Errorf("error parsing root-ca-file at %s: %v", s.RootCAFile, err)
}
} else {
rootCA = kubeconfig.CAData
}
if len(s.ServiceAccountKeyFile) > 0 {
privateKey, err := serviceaccount.ReadPrivateKey(s.ServiceAccountKeyFile)
if err != nil {
@ -250,9 +268,10 @@ func (s *CMServer) Run(_ []string) error {
} else {
serviceaccount.NewTokensController(
kubeClient,
serviceaccount.DefaultTokenControllerOptions(
serviceaccount.JWTTokenGenerator(privateKey),
),
serviceaccount.TokensControllerOptions{
TokenGenerator: serviceaccount.JWTTokenGenerator(privateKey),
RootCA: rootCA,
},
).Run()
}
}

View File

@ -157,9 +157,10 @@ func (s *CMServer) Run(_ []string) error {
} else {
serviceaccount.NewTokensController(
kubeClient,
serviceaccount.DefaultTokenControllerOptions(
serviceaccount.JWTTokenGenerator(privateKey),
),
serviceaccount.TokensControllerOptions{
TokenGenerator: serviceaccount.JWTTokenGenerator(privateKey),
RootCA: kubeconfig.CAData,
},
).Run()
}
}

View File

@ -1961,6 +1961,8 @@ const (
ServiceAccountTokenKey = "token"
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
// ServiceAccountRootCAKey is the key of the optional root certificate authority for SecretTypeServiceAccountToken secrets
ServiceAccountRootCAKey = "ca.crt"
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
//

View File

@ -1862,6 +1862,8 @@ const (
ServiceAccountTokenKey = "token"
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
// ServiceAccountRootCAKey is the key of the optional root certificate authority for SecretTypeServiceAccountToken secrets
ServiceAccountRootCAKey = "ca.crt"
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
//

View File

@ -1868,6 +1868,8 @@ const (
ServiceAccountTokenKey = "token"
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
// ServiceAccountRootCAKey is the key of the optional root certificate authority for SecretTypeServiceAccountToken secrets
ServiceAccountRootCAKey = "ca.crt"
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
//

View File

@ -29,6 +29,7 @@ import (
"strings"
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/registered"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
@ -236,17 +237,24 @@ func NewOrDie(c *Config) *Client {
// running inside a pod running on kuberenetes. It will return an error if
// called from a process not running in a kubernetes environment.
func InClusterConfig() (*Config, error) {
token, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
token, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountTokenKey)
if err != nil {
return nil, err
}
tlsClientConfig := TLSClientConfig{}
rootCAFile := "/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountRootCAKey
if _, err := util.CertPoolFromFile(rootCAFile); err != nil {
glog.Errorf("expected to load root ca config from %s, but got err: %v", rootCAFile, err)
} else {
tlsClientConfig.CAFile = rootCAFile
}
return &Config{
// TODO: switch to using cluster DNS.
Host: "https://" + net.JoinHostPort(os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")),
Version: "v1beta3",
BearerToken: string(token),
// TODO: package certs along with the token
Insecure: true,
Host: "https://" + net.JoinHostPort(os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")),
Version: "v1beta3",
BearerToken: string(token),
TLSClientConfig: tlsClientConfig,
}, nil
}

View File

@ -44,11 +44,8 @@ type TokensControllerOptions struct {
// SecretResync is the time.Duration at which to fully re-list secrets.
// If zero, re-list will be delayed as long as possible
SecretResync time.Duration
}
// DefaultTokenControllerOptions returns
func DefaultTokenControllerOptions(tokenGenerator TokenGenerator) TokensControllerOptions {
return TokensControllerOptions{TokenGenerator: tokenGenerator}
// This CA will be added in the secretes of service accounts
RootCA []byte
}
// NewTokensController returns a new *TokensController.
@ -56,6 +53,7 @@ func NewTokensController(cl client.Interface, options TokensControllerOptions) *
e := &TokensController{
client: cl,
token: options.TokenGenerator,
rootCA: options.RootCA,
}
e.serviceAccounts, e.serviceAccountController = framework.NewIndexerInformer(
@ -110,6 +108,8 @@ type TokensController struct {
client client.Interface
token TokenGenerator
rootCA []byte
serviceAccounts cache.Indexer
secrets cache.Indexer
@ -293,6 +293,9 @@ func (e *TokensController) createSecret(serviceAccount *api.ServiceAccount) erro
return err
}
secret.Data[api.ServiceAccountTokenKey] = []byte(token)
if e.rootCA != nil && len(e.rootCA) > 0 {
secret.Data[api.ServiceAccountRootCAKey] = e.rootCA
}
// Save the secret
if _, err := e.client.Secrets(serviceAccount.Namespace).Create(secret); err != nil {
@ -337,6 +340,9 @@ func (e *TokensController) generateTokenIfNeeded(serviceAccount *api.ServiceAcco
if ok && len(tokenData) > 0 {
return nil
}
if e.rootCA != nil && len(e.rootCA) > 0 {
secret.Data[api.ServiceAccountRootCAKey] = e.rootCA
}
// Generate the token
token, err := e.token.GenerateToken(*serviceAccount, *secret)

View File

@ -378,7 +378,7 @@ func TestTokenCreation(t *testing.T) {
client := testclient.NewSimpleFake(tc.ClientObjects...)
controller := NewTokensController(client, DefaultTokenControllerOptions(generator))
controller := NewTokensController(client, TokensControllerOptions{TokenGenerator: generator})
// Tell the token controller whether its stores have been synced
controller.serviceAccountsSynced = func() bool { return !tc.ServiceAccountsSyncPending }

View File

@ -123,16 +123,16 @@ func certificatesFromFile(file string) ([]*x509.Certificate, error) {
if err != nil {
return nil, err
}
certs, err := certsFromPEM(pemBlock)
certs, err := CertsFromPEM(pemBlock)
if err != nil {
return nil, fmt.Errorf("error reading %s: %s", file, err)
}
return certs, nil
}
// certsFromPEM returns the x509.Certificates contained in the given PEM-encoded byte array
// CertsFromPEM returns the x509.Certificates contained in the given PEM-encoded byte array
// Returns an error if a certificate could not be parsed, or if the data does not contain any certificates
func certsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) {
func CertsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) {
ok := false
certs := []*x509.Certificate{}
for len(pemCerts) > 0 {

View File

@ -422,7 +422,7 @@ func startServiceAccountTestServer(t *testing.T) (*client.Client, client.Config,
})
// Start the service account and service account token controllers
tokenController := serviceaccount.NewTokensController(rootClient, serviceaccount.DefaultTokenControllerOptions(serviceaccount.JWTTokenGenerator(serviceAccountKey)))
tokenController := serviceaccount.NewTokensController(rootClient, serviceaccount.TokensControllerOptions{TokenGenerator: serviceaccount.JWTTokenGenerator(serviceAccountKey)})
tokenController.Run()
serviceAccountController := serviceaccount.NewServiceAccountsController(rootClient, serviceaccount.DefaultServiceAccountsControllerOptions())
serviceAccountController.Run()