mirror of https://github.com/kubernetes/kops.git
Merge pull request #15125 from justinsb/node_challenge
Perform challenge callbacks into a node
This commit is contained in:
commit
68dcc7ad48
|
|
@ -36,6 +36,8 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kops/cmd/kops-controller/pkg/config"
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/pkg/apis/kops/model"
|
||||
"k8s.io/kops/pkg/apis/nodeup"
|
||||
"k8s.io/kops/pkg/bootstrap"
|
||||
"k8s.io/kops/pkg/pki"
|
||||
|
|
@ -61,6 +63,9 @@ type Server struct {
|
|||
|
||||
// uncachedClient is an uncached client for the kube apiserver
|
||||
uncachedClient client.Client
|
||||
|
||||
// challengeClient performs our callback-challenge into the node
|
||||
challengeClient *bootstrap.ChallengeClient
|
||||
}
|
||||
|
||||
var _ manager.LeaderElectionRunnable = &Server{}
|
||||
|
|
@ -94,6 +99,17 @@ func NewServer(opt *config.Options, verifier bootstrap.Verifier, uncachedClient
|
|||
}
|
||||
s.secretStore = secrets.NewVFSSecretStore(nil, p)
|
||||
|
||||
s.keystore, s.keypairIDs, err = newKeystore(opt.Server.CABasePath, opt.Server.SigningCAs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
challengeClient, err := bootstrap.NewChallengeClient(s.keystore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.challengeClient = challengeClient
|
||||
|
||||
r := http.NewServeMux()
|
||||
r.Handle("/bootstrap", http.HandlerFunc(s.bootstrap))
|
||||
server.Handler = recovery(r)
|
||||
|
|
@ -106,12 +122,6 @@ func (s *Server) NeedLeaderElection() bool {
|
|||
}
|
||||
|
||||
func (s *Server) Start(ctx context.Context) error {
|
||||
var err error
|
||||
s.keystore, s.keypairIDs, err = newKeystore(s.opt.Server.CABasePath, s.opt.Server.SigningCAs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
|
||||
|
|
@ -198,6 +208,17 @@ func (s *Server) bootstrap(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if model.UseChallengeCallback(kops.CloudProviderID(s.opt.Cloud)) {
|
||||
if err := s.challengeClient.DoCallbackChallenge(ctx, s.opt.ClusterName, id.ChallengeEndpoint, req); err != nil {
|
||||
klog.Infof("bootstrap %s callback challenge failed: %v", r.RemoteAddr, err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
_, _ = w.Write([]byte("callback failed"))
|
||||
return
|
||||
}
|
||||
|
||||
klog.Infof("performed successful callback challenge with %s; identified as %s", id.ChallengeEndpoint, id.NodeName)
|
||||
}
|
||||
|
||||
resp := &nodeup.BootstrapResponse{
|
||||
Certs: map[string]string{},
|
||||
}
|
||||
|
|
|
|||
4
go.mod
4
go.mod
|
|
@ -54,6 +54,8 @@ require (
|
|||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/sys v0.6.0
|
||||
google.golang.org/api v0.112.0
|
||||
google.golang.org/grpc v1.53.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
gopkg.in/gcfg.v1 v1.2.3
|
||||
gopkg.in/inf.v0 v0.9.1
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
|
|
@ -213,8 +215,6 @@ require (
|
|||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488 // indirect
|
||||
google.golang.org/grpc v1.53.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ func (b BootstrapClientBuilder) Build(c *fi.NodeupModelBuilderContext) error {
|
|||
var authenticator bootstrap.Authenticator
|
||||
var resolver resolver.Resolver
|
||||
|
||||
switch b.BootConfig.CloudProvider {
|
||||
switch b.CloudProvider() {
|
||||
case kops.CloudProviderAWS:
|
||||
a, err := awsup.NewAWSAuthenticator(b.Cloud.Region())
|
||||
if err != nil {
|
||||
|
|
@ -81,7 +81,7 @@ func (b BootstrapClientBuilder) Build(c *fi.NodeupModelBuilderContext) error {
|
|||
authenticator = a
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unsupported cloud provider for authenticator %q", b.BootConfig.CloudProvider)
|
||||
return fmt.Errorf("unsupported cloud provider for authenticator %q", b.CloudProvider())
|
||||
}
|
||||
|
||||
baseURL := url.URL{
|
||||
|
|
@ -102,6 +102,8 @@ func (b BootstrapClientBuilder) Build(c *fi.NodeupModelBuilderContext) error {
|
|||
Certs: b.bootstrapCerts,
|
||||
KeypairIDs: b.bootstrapKeypairIDs,
|
||||
}
|
||||
bootstrapClientTask.UseChallengeCallback = b.UseChallengeCallback(b.CloudProvider())
|
||||
bootstrapClientTask.ClusterName = b.NodeupConfig.ClusterName
|
||||
|
||||
for _, cert := range b.bootstrapCerts {
|
||||
cert.Cert.Task = bootstrapClientTask
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ func (b *CloudConfigBuilder) build(c *fi.NodeupModelBuilderContext, inTree bool)
|
|||
// Add cloud config file if needed
|
||||
var lines []string
|
||||
|
||||
cloudProvider := b.BootConfig.CloudProvider
|
||||
cloudProvider := b.CloudProvider()
|
||||
|
||||
var config string
|
||||
requireGlobal := true
|
||||
|
|
|
|||
|
|
@ -396,6 +396,11 @@ func (c *NodeupModelContext) UseKopsControllerForNodeBootstrap() bool {
|
|||
return model.UseKopsControllerForNodeBootstrap(c.Cluster)
|
||||
}
|
||||
|
||||
// UseChallengeCallback is true if we should use a callback challenge during node provisioning with kops-controller.
|
||||
func (c *NodeupModelContext) UseChallengeCallback(cloudProvider kops.CloudProviderID) bool {
|
||||
return model.UseChallengeCallback(cloudProvider)
|
||||
}
|
||||
|
||||
// UsesSecondaryIP checks if the CNI in use attaches secondary interfaces to the host.
|
||||
func (c *NodeupModelContext) UsesSecondaryIP() bool {
|
||||
return (c.NodeupConfig.Networking.CNI != nil && c.NodeupConfig.Networking.CNI.UsesSecondaryIP) ||
|
||||
|
|
@ -630,14 +635,19 @@ func (c *NodeupModelContext) InstallNvidiaRuntime() bool {
|
|||
c.GPUVendor == architectures.GPUVendorNvidia
|
||||
}
|
||||
|
||||
// CloudProvider returns the cloud provider we are running on
|
||||
func (c *NodeupModelContext) CloudProvider() kops.CloudProviderID {
|
||||
return c.BootConfig.CloudProvider
|
||||
}
|
||||
|
||||
// RunningOnGCE returns true if we are running on GCE
|
||||
func (c *NodeupModelContext) RunningOnGCE() bool {
|
||||
return c.BootConfig.CloudProvider == kops.CloudProviderGCE
|
||||
return c.CloudProvider() == kops.CloudProviderGCE
|
||||
}
|
||||
|
||||
// RunningOnAzure returns true if we are running on Azure
|
||||
func (c *NodeupModelContext) RunningOnAzure() bool {
|
||||
return c.BootConfig.CloudProvider == kops.CloudProviderAzure
|
||||
return c.CloudProvider() == kops.CloudProviderAzure
|
||||
}
|
||||
|
||||
// GetMetadataLocalIP returns the local IP address read from metadata
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ func (b *KubeAPIServerBuilder) Build(c *fi.NodeupModelBuilderContext) error {
|
|||
kubeAPIServer = *b.NodeupConfig.APIServerConfig.KubeAPIServer
|
||||
}
|
||||
|
||||
if b.BootConfig.CloudProvider == kops.CloudProviderHetzner {
|
||||
if b.CloudProvider() == kops.CloudProviderHetzner {
|
||||
localIP, err := b.GetMetadataLocalIP()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -419,7 +419,7 @@ func (b *KubeAPIServerBuilder) writeServerCertificate(c *fi.NodeupModelBuilderCo
|
|||
// We also want to be able to reference it locally via https://127.0.0.1
|
||||
alternateNames = append(alternateNames, "127.0.0.1")
|
||||
|
||||
if b.BootConfig.CloudProvider == kops.CloudProviderHetzner {
|
||||
if b.CloudProvider() == kops.CloudProviderHetzner {
|
||||
localIP, err := b.GetMetadataLocalIP()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -428,7 +428,7 @@ func (b *KubeAPIServerBuilder) writeServerCertificate(c *fi.NodeupModelBuilderCo
|
|||
alternateNames = append(alternateNames, localIP)
|
||||
}
|
||||
}
|
||||
if b.BootConfig.CloudProvider == kops.CloudProviderOpenstack {
|
||||
if b.CloudProvider() == kops.CloudProviderOpenstack {
|
||||
instanceAddress, err := getInstanceAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -737,7 +737,7 @@ func (b *KubeletBuilder) buildKubeletServingCertificate(c *fi.NodeupModelBuilder
|
|||
}
|
||||
|
||||
func (b *KubeletBuilder) kubeletNames() ([]string, error) {
|
||||
if b.BootConfig.CloudProvider != kops.CloudProviderAWS {
|
||||
if b.CloudProvider() != kops.CloudProviderAWS {
|
||||
name, err := os.Hostname()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func (b *NTPBuilder) Build(c *fi.NodeupModelBuilderContext) error {
|
|||
}
|
||||
|
||||
var ntpHost string
|
||||
switch b.BootConfig.CloudProvider {
|
||||
switch b.CloudProvider() {
|
||||
case kops.CloudProviderAWS:
|
||||
ntpHost = "169.254.169.123"
|
||||
case kops.CloudProviderGCE:
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ func (b *PrefixBuilder) Build(c *fi.NodeupModelBuilderContext) error {
|
|||
if !b.IsKopsControllerIPAM() {
|
||||
return nil
|
||||
}
|
||||
switch b.BootConfig.CloudProvider {
|
||||
switch b.CloudProvider() {
|
||||
case kops.CloudProviderAWS:
|
||||
c.AddTask(&nodetasks.Prefix{
|
||||
Name: "prefix",
|
||||
|
|
@ -42,7 +42,7 @@ func (b *PrefixBuilder) Build(c *fi.NodeupModelBuilderContext) error {
|
|||
case kops.CloudProviderGCE:
|
||||
// Prefix is assigned by GCE
|
||||
default:
|
||||
return fmt.Errorf("kOps IPAM controller not supported on cloud %q", b.BootConfig.CloudProvider)
|
||||
return fmt.Errorf("kOps IPAM controller not supported on cloud %q", b.CloudProvider())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ type ProtokubeFlags struct {
|
|||
func (t *ProtokubeBuilder) ProtokubeFlags() (*ProtokubeFlags, error) {
|
||||
f := &ProtokubeFlags{
|
||||
Channels: t.NodeupConfig.Channels,
|
||||
Cloud: fi.PtrTo(string(t.BootConfig.CloudProvider)),
|
||||
Cloud: fi.PtrTo(string(t.CloudProvider())),
|
||||
Containerized: fi.PtrTo(false),
|
||||
LogLevel: fi.PtrTo(int32(4)),
|
||||
Master: b(t.IsMaster),
|
||||
|
|
@ -273,7 +273,7 @@ func (t *ProtokubeBuilder) buildEnvFile() (*nodetasks.File, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if t.BootConfig.CloudProvider == kops.CloudProviderDO && os.Getenv("DIGITALOCEAN_ACCESS_TOKEN") != "" {
|
||||
if t.CloudProvider() == kops.CloudProviderDO && os.Getenv("DIGITALOCEAN_ACCESS_TOKEN") != "" {
|
||||
envVars["DIGITALOCEAN_ACCESS_TOKEN"] = os.Getenv("DIGITALOCEAN_ACCESS_TOKEN")
|
||||
}
|
||||
|
||||
|
|
@ -294,7 +294,7 @@ func (t *ProtokubeBuilder) buildEnvFile() (*nodetasks.File, error) {
|
|||
envVars["AZURE_STORAGE_ACCOUNT"] = os.Getenv("AZURE_STORAGE_ACCOUNT")
|
||||
}
|
||||
|
||||
if t.BootConfig.CloudProvider == kops.CloudProviderScaleway {
|
||||
if t.CloudProvider() == kops.CloudProviderScaleway {
|
||||
if os.Getenv("SCW_PROFILE") != "" || os.Getenv("SCW_SECRET_KEY") != "" {
|
||||
profile, err := scaleway.CreateValidScalewayProfile()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ func (b *SysctlBuilder) Build(c *fi.NodeupModelBuilderContext) error {
|
|||
)
|
||||
}
|
||||
|
||||
if b.BootConfig.CloudProvider == kops.CloudProviderAWS {
|
||||
if b.CloudProvider() == kops.CloudProviderAWS {
|
||||
sysctls = append(sysctls,
|
||||
"# AWS settings",
|
||||
"",
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ var _ fi.NodeupModelBuilder = &WarmPoolBuilder{}
|
|||
|
||||
func (b *WarmPoolBuilder) Build(c *fi.NodeupModelBuilderContext) error {
|
||||
// Check if the cloud provider is AWS
|
||||
if b.BootConfig.CloudProvider != kops.CloudProviderAWS {
|
||||
if b.CloudProvider() != kops.CloudProviderAWS {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,16 @@ func UseKopsControllerForNodeBootstrap(cluster *kops.Cluster) bool {
|
|||
}
|
||||
}
|
||||
|
||||
// UseChallengeCallback is true if we should use a callback challenge during node provisioning with kops-controller.
|
||||
func UseChallengeCallback(cloudProvider kops.CloudProviderID) bool {
|
||||
switch cloudProvider {
|
||||
case kops.CloudProviderHetzner:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// UseKopsControllerForNodeConfig checks if nodeup should use kops-controller to get nodeup.Config.
|
||||
func UseKopsControllerForNodeConfig(cluster *kops.Cluster) bool {
|
||||
switch cluster.Spec.GetCloudProvider() {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,17 @@ type BootstrapRequest struct {
|
|||
// IncludeNodeConfig controls whether the cluster & instance group configuration should be returned.
|
||||
// This allows for nodes without access to the kops state store.
|
||||
IncludeNodeConfig bool `json:"includeNodeConfig"`
|
||||
|
||||
// Challenge is for a callback challenge.
|
||||
Challenge *ChallengeRequest `json:"challenge,omitempty"`
|
||||
}
|
||||
|
||||
// ChallengeRequest describes the callback challenge.
|
||||
type ChallengeRequest struct {
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
ServerCA []byte `json:"ca,omitempty"`
|
||||
ChallengeID string `json:"challengeID,omitempty"`
|
||||
ChallengeSecret []byte `json:"challengeSecret,omitempty"`
|
||||
}
|
||||
|
||||
// BootstrapResponse is a response to a BootstrapRequest.
|
||||
|
|
|
|||
|
|
@ -127,6 +127,8 @@ type BootConfig struct {
|
|||
// APIServerIPs is the API server IP addresses.
|
||||
// This field is used for adding an alias for api.internal. in /etc/hosts, when Topology.DNS.Type == DNSTypeNone.
|
||||
APIServerIPs []string `json:",omitempty"`
|
||||
// ClusterName is the name of the cluster.
|
||||
ClusterName string `json:",omitempty"`
|
||||
// InstanceGroupName is the name of the instance group.
|
||||
InstanceGroupName string `json:",omitempty"`
|
||||
// InstanceGroupRole is the instance group role.
|
||||
|
|
@ -200,6 +202,7 @@ func NewConfig(cluster *kops.Cluster, instanceGroup *kops.InstanceGroup) (*Confi
|
|||
|
||||
bootConfig := BootConfig{
|
||||
CloudProvider: cluster.Spec.GetCloudProvider(),
|
||||
ClusterName: cluster.ObjectMeta.Name,
|
||||
InstanceGroupName: instanceGroup.ObjectMeta.Name,
|
||||
InstanceGroupRole: role,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ type VerifyResult struct {
|
|||
|
||||
// CertificateNames is the alternate names the node is authorized to use for certificates.
|
||||
CertificateNames []string
|
||||
|
||||
// ChallengeEndpoint is a valid endpoints to which we should issue a challenge request,
|
||||
// corresponding to the node the request identified as.
|
||||
// This should be sourced from e.g. the cloud, and acts as a cross-check
|
||||
// that this is the correct instance.
|
||||
ChallengeEndpoint string
|
||||
}
|
||||
|
||||
// Verifier verifies authentication credentials for requests.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
Copyright 2023 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.
|
||||
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 bootstrap
|
||||
|
||||
import (
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kops/pkg/pki"
|
||||
)
|
||||
|
||||
func randomBytes(length int) []byte {
|
||||
b := make([]byte, length)
|
||||
if _, err := cryptorand.Read(b); err != nil {
|
||||
klog.Fatalf("failed to read from crypto/rand: %v", err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func challengeKopsControllerSubject(clusterName string) pkix.Name {
|
||||
// Note: keep in sync with subjectsMatch if you add (additional) fields here
|
||||
return pkix.Name{
|
||||
CommonName: "kops-controller." + clusterName,
|
||||
}
|
||||
}
|
||||
|
||||
func subjectsMatch(l, r pkix.Name) bool {
|
||||
// We need to check all the fields in challengeKopsControllerSubject
|
||||
return l.CommonName == r.CommonName
|
||||
}
|
||||
|
||||
func challengeServerHostName(clusterName string) string {
|
||||
return "challenge-server." + clusterName
|
||||
}
|
||||
|
||||
func BuildChallengeServerCertificate(clusterName string) (*tls.Certificate, error) {
|
||||
serverName := challengeServerHostName(clusterName)
|
||||
|
||||
privateKey, err := pki.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("generating ecdsa key: %w", err)
|
||||
}
|
||||
|
||||
keyUsage := x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment
|
||||
|
||||
now := time.Now()
|
||||
notBefore := now.Add(-15 * time.Minute)
|
||||
notAfter := notBefore.Add(time.Hour)
|
||||
|
||||
template := x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{
|
||||
CommonName: serverName,
|
||||
},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
|
||||
KeyUsage: keyUsage,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
|
||||
template.DNSNames = append(template.DNSNames, serverName)
|
||||
|
||||
der, err := x509.CreateCertificate(cryptorand.Reader, &template, &template, privateKey.Key.Public(), privateKey.Key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create certificate: %w", err)
|
||||
}
|
||||
|
||||
parsed, err := x509.ParseCertificate(der)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse certificate: %w", err)
|
||||
}
|
||||
tlsCertificate := &tls.Certificate{
|
||||
PrivateKey: privateKey.Key,
|
||||
Certificate: [][]byte{parsed.Raw},
|
||||
Leaf: parsed,
|
||||
}
|
||||
|
||||
return tlsCertificate, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
Copyright 2023 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.
|
||||
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 bootstrap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/subtle"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"k8s.io/kops/pkg/apis/nodeup"
|
||||
"k8s.io/kops/pkg/pki"
|
||||
pb "k8s.io/kops/proto/kops/bootstrap/v1"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
)
|
||||
|
||||
type ChallengeClient struct {
|
||||
keystore pki.Keystore
|
||||
}
|
||||
|
||||
func NewChallengeClient(keystore pki.Keystore) (*ChallengeClient, error) {
|
||||
return &ChallengeClient{
|
||||
keystore: keystore,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *ChallengeClient) getClientCertificate(ctx context.Context, clusterName string) (*tls.Certificate, error) {
|
||||
subject := challengeKopsControllerSubject(clusterName)
|
||||
|
||||
certificate, privateKey, _, err := pki.IssueCert(ctx, &pki.IssueCertRequest{
|
||||
Validity: 1 * time.Hour,
|
||||
Signer: fi.CertificateIDCA,
|
||||
Type: "client",
|
||||
Subject: subject,
|
||||
}, c.keystore)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating certificate: %w", err)
|
||||
}
|
||||
|
||||
// TODO: Caching and rotation
|
||||
clientCertificate := &tls.Certificate{
|
||||
PrivateKey: privateKey.Key,
|
||||
Certificate: [][]byte{certificate.Certificate.Raw},
|
||||
Leaf: certificate.Certificate,
|
||||
}
|
||||
return clientCertificate, nil
|
||||
}
|
||||
|
||||
func (c *ChallengeClient) DoCallbackChallenge(ctx context.Context, clusterName string, targetEndpoint string, bootstrapRequest *nodeup.BootstrapRequest) error {
|
||||
challenge := bootstrapRequest.Challenge
|
||||
|
||||
if challenge == nil {
|
||||
return fmt.Errorf("challenge not set")
|
||||
}
|
||||
if challenge.ChallengeID == "" {
|
||||
return fmt.Errorf("challenge.id not set")
|
||||
}
|
||||
if len(challenge.ChallengeSecret) == 0 {
|
||||
return fmt.Errorf("challenge.secret not set")
|
||||
}
|
||||
if challenge.Endpoint == "" {
|
||||
return fmt.Errorf("challenge.endpoint not set")
|
||||
}
|
||||
if len(challenge.ServerCA) == 0 {
|
||||
return fmt.Errorf("challenge.ca not set")
|
||||
}
|
||||
|
||||
clientCertificate, err := c.getClientCertificate(ctx, clusterName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverCAs := x509.NewCertPool()
|
||||
if !serverCAs.AppendCertsFromPEM(challenge.ServerCA) {
|
||||
return fmt.Errorf("error loading certificate pool")
|
||||
}
|
||||
|
||||
serverName := challengeServerHostName(clusterName)
|
||||
tlsConfig := &tls.Config{
|
||||
RootCAs: serverCAs,
|
||||
Certificates: []tls.Certificate{*clientCertificate},
|
||||
ServerName: serverName,
|
||||
}
|
||||
|
||||
kospControllerNonce := randomBytes(16)
|
||||
req := &pb.ChallengeRequest{
|
||||
ChallengeId: challenge.ChallengeID,
|
||||
ChallengeRandom: kospControllerNonce,
|
||||
}
|
||||
|
||||
expectedChallengeResponse := buildChallengeResponse(challenge.ChallengeSecret, kospControllerNonce)
|
||||
|
||||
var opts []grpc.DialOption
|
||||
opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)))
|
||||
conn, err := grpc.DialContext(ctx, targetEndpoint, opts...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error dialing target %q: %w", targetEndpoint, err)
|
||||
}
|
||||
client := pb.NewCallbackServiceClient(conn)
|
||||
|
||||
response, err := client.Challenge(ctx, req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error from callback challenge: %w", err)
|
||||
}
|
||||
|
||||
if subtle.ConstantTimeCompare(response.GetChallengeResponse(), expectedChallengeResponse) != 1 {
|
||||
return fmt.Errorf("callback challenge returned wrong result")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
Copyright 2023 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.
|
||||
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 bootstrap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/peer"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kops/pkg/apis/nodeup"
|
||||
pb "k8s.io/kops/proto/kops/bootstrap/v1"
|
||||
)
|
||||
|
||||
type ChallengeServer struct {
|
||||
tlsConfig *tls.Config
|
||||
servingCA []byte
|
||||
|
||||
mutex sync.Mutex
|
||||
challenges map[string]*Challenge
|
||||
|
||||
RequiredSubject pkix.Name
|
||||
|
||||
pb.UnimplementedCallbackServiceServer
|
||||
}
|
||||
|
||||
func NewChallengeServer(clusterName string, caBundle []byte) (*ChallengeServer, error) {
|
||||
serverCertificate, err := BuildChallengeServerCertificate(clusterName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig := &tls.Config{
|
||||
Certificates: []tls.Certificate{*serverCertificate},
|
||||
}
|
||||
|
||||
var servingCA bytes.Buffer
|
||||
for _, cert := range serverCertificate.Certificate {
|
||||
if err := pem.Encode(&servingCA, &pem.Block{Type: "CERTIFICATE", Bytes: cert}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
clientCAs := x509.NewCertPool()
|
||||
if !clientCAs.AppendCertsFromPEM(caBundle) {
|
||||
return nil, fmt.Errorf("unable to build client-cert CA pools")
|
||||
}
|
||||
tlsConfig.ClientCAs = clientCAs
|
||||
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
|
||||
return &ChallengeServer{
|
||||
RequiredSubject: challengeKopsControllerSubject(clusterName),
|
||||
tlsConfig: tlsConfig,
|
||||
servingCA: servingCA.Bytes(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Challenge struct {
|
||||
ChallengeID string
|
||||
ChallengeSecret []byte
|
||||
}
|
||||
|
||||
func (s *ChallengeServer) createChallenge() *Challenge {
|
||||
c := &Challenge{}
|
||||
c.ChallengeID = hex.EncodeToString(randomBytes(16))
|
||||
c.ChallengeSecret = randomBytes(16)
|
||||
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
if s.challenges == nil {
|
||||
s.challenges = make(map[string]*Challenge)
|
||||
}
|
||||
s.challenges[c.ChallengeID] = c
|
||||
return c
|
||||
}
|
||||
|
||||
type ChallengeListener struct {
|
||||
endpoint string
|
||||
server *ChallengeServer
|
||||
grpcServer *grpc.Server
|
||||
}
|
||||
|
||||
func (s *ChallengeListener) CreateChallenge() *nodeup.ChallengeRequest {
|
||||
challenge := s.server.createChallenge()
|
||||
|
||||
return &nodeup.ChallengeRequest{
|
||||
Endpoint: s.Endpoint(),
|
||||
ChallengeID: challenge.ChallengeID,
|
||||
ChallengeSecret: challenge.ChallengeSecret,
|
||||
ServerCA: s.server.servingCA,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ChallengeListener) Stop() {
|
||||
s.grpcServer.Stop()
|
||||
}
|
||||
|
||||
func (s *ChallengeListener) Endpoint() string {
|
||||
return s.endpoint
|
||||
}
|
||||
|
||||
func (s *ChallengeServer) NewListener(ctx context.Context, listen string) (*ChallengeListener, error) {
|
||||
var opts []grpc.ServerOption
|
||||
|
||||
opts = append(opts, grpc.Creds(credentials.NewTLS(s.tlsConfig)))
|
||||
grpcServer := grpc.NewServer(opts...)
|
||||
pb.RegisterCallbackServiceServer(grpcServer, s)
|
||||
|
||||
lis, err := net.Listen("tcp", listen)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listening on %q: %w", listen, err)
|
||||
}
|
||||
|
||||
grpcListener := &ChallengeListener{
|
||||
server: s,
|
||||
grpcServer: grpcServer,
|
||||
endpoint: lis.Addr().String(),
|
||||
}
|
||||
|
||||
go func() {
|
||||
klog.Infof("starting node-challenge listener on %v", lis.Addr())
|
||||
if err := grpcServer.Serve(lis); err != nil {
|
||||
lis.Close()
|
||||
|
||||
klog.Warningf("error serving GRPC: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return grpcListener, nil
|
||||
}
|
||||
|
||||
// Answers challenges to cross-check bootstrap requests.
|
||||
func (s *ChallengeServer) Challenge(ctx context.Context, req *pb.ChallengeRequest) (*pb.ChallengeResponse, error) {
|
||||
klog.Infof("got node-challenge request")
|
||||
// Explicitly authenticate the username for safety
|
||||
peerInfo, ok := peer.FromContext(ctx)
|
||||
if !ok {
|
||||
klog.Warningf("no peer in context")
|
||||
return nil, status.Error(codes.Unauthenticated, "peer was nil")
|
||||
}
|
||||
|
||||
tlsInfo, ok := peerInfo.AuthInfo.(credentials.TLSInfo)
|
||||
if !ok {
|
||||
klog.Warningf("peer.AuthInfo was of unexpected type %T", peerInfo.AuthInfo)
|
||||
return nil, status.Error(codes.Unauthenticated, "unexpected peer transport credentials")
|
||||
}
|
||||
|
||||
if len(tlsInfo.State.VerifiedChains) == 0 || len(tlsInfo.State.VerifiedChains[0]) == 0 {
|
||||
klog.Warningf("no VerifiedChains in TLSInfo")
|
||||
return nil, status.Error(codes.Unauthenticated, "verified chains were empty")
|
||||
}
|
||||
|
||||
if got, want := tlsInfo.State.VerifiedChains[0][0].Subject, s.RequiredSubject; !subjectsMatch(got, want) {
|
||||
klog.Warningf("certificate subjects did not match expected; got %q, want %q", got, want)
|
||||
return nil, status.Error(codes.Unauthenticated, "certificate subjects did not match")
|
||||
}
|
||||
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
|
||||
key := req.ChallengeId
|
||||
if key == "" {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "challenge_id is required")
|
||||
}
|
||||
|
||||
challenge := s.challenges[key]
|
||||
if challenge == nil {
|
||||
return nil, status.Errorf(codes.NotFound, "challenge was not found")
|
||||
}
|
||||
// Prevent replay attacks
|
||||
delete(s.challenges, key)
|
||||
|
||||
hash := buildChallengeResponse(challenge.ChallengeSecret, req.GetChallengeRandom())
|
||||
response := &pb.ChallengeResponse{
|
||||
ChallengeResponse: hash,
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func buildChallengeResponse(nodeNonce []byte, kopsControllerNonde []byte) []byte {
|
||||
// Arguably this is overkill because the TLS handshake is stronger and everything is encrypted.
|
||||
hasher := sha256.New()
|
||||
hasher.Sum(nodeNonce)
|
||||
hasher.Sum(kopsControllerNonde)
|
||||
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
return hash
|
||||
}
|
||||
|
|
@ -20,6 +20,9 @@ const (
|
|||
// KubeAPIServer is the port where kube-apiserver listens.
|
||||
KubeAPIServer = 443
|
||||
|
||||
// NodeupChallenge is the port where nodeup listens for challenges.
|
||||
NodeupChallenge = 3987
|
||||
|
||||
// KopsControllerPort is the port where kops-controller listens.
|
||||
KopsControllerPort = 3988
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
version: v1
|
||||
plugins:
|
||||
- plugin: go
|
||||
out: .
|
||||
opt: paths=source_relative
|
||||
- plugin: go-grpc
|
||||
out: .
|
||||
opt: paths=source_relative
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
version: v1
|
||||
breaking:
|
||||
use:
|
||||
- FILE
|
||||
lint:
|
||||
use:
|
||||
- DEFAULT
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
Copyright 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.
|
||||
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.
|
||||
*/
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.0
|
||||
// protoc (unknown)
|
||||
// source: kops/bootstrap/v1/bootstrap.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type ChallengeRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// challenge_id is a random value (nonce) that the node generated and passed in its bootstrap request.
|
||||
ChallengeId string `protobuf:"bytes,1,opt,name=challenge_id,json=challengeId,proto3" json:"challenge_id,omitempty"`
|
||||
// challenge_random is a random value (nonce) that kops-controller generated, it is hashed into the response.
|
||||
ChallengeRandom []byte `protobuf:"bytes,2,opt,name=challenge_random,json=challengeRandom,proto3" json:"challenge_random,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ChallengeRequest) Reset() {
|
||||
*x = ChallengeRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_kops_bootstrap_v1_bootstrap_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ChallengeRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ChallengeRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ChallengeRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_kops_bootstrap_v1_bootstrap_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ChallengeRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ChallengeRequest) Descriptor() ([]byte, []int) {
|
||||
return file_kops_bootstrap_v1_bootstrap_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *ChallengeRequest) GetChallengeId() string {
|
||||
if x != nil {
|
||||
return x.ChallengeId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ChallengeRequest) GetChallengeRandom() []byte {
|
||||
if x != nil {
|
||||
return x.ChallengeRandom
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ChallengeResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// challenge_response combines the node nonce with the kops-controller nonce.
|
||||
// The node nonce is passed in the bootstrap request.
|
||||
// The kops-controller nonce is challenge_random in the ChallengeRequest.
|
||||
// challenge_response is expected to be sha256(node-node + kops-controller-nonce)
|
||||
ChallengeResponse []byte `protobuf:"bytes,1,opt,name=challenge_response,json=challengeResponse,proto3" json:"challenge_response,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ChallengeResponse) Reset() {
|
||||
*x = ChallengeResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_kops_bootstrap_v1_bootstrap_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ChallengeResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ChallengeResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ChallengeResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_kops_bootstrap_v1_bootstrap_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ChallengeResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ChallengeResponse) Descriptor() ([]byte, []int) {
|
||||
return file_kops_bootstrap_v1_bootstrap_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *ChallengeResponse) GetChallengeResponse() []byte {
|
||||
if x != nil {
|
||||
return x.ChallengeResponse
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_kops_bootstrap_v1_bootstrap_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_kops_bootstrap_v1_bootstrap_proto_rawDesc = []byte{
|
||||
0x0a, 0x21, 0x6b, 0x6f, 0x70, 0x73, 0x2f, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70,
|
||||
0x2f, 0x76, 0x31, 0x2f, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x12, 0x11, 0x6b, 0x6f, 0x70, 0x73, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74,
|
||||
0x72, 0x61, 0x70, 0x2e, 0x76, 0x31, 0x22, 0x60, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65,
|
||||
0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x68,
|
||||
0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0b, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x49, 0x64, 0x12, 0x29, 0x0a,
|
||||
0x10, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x64, 0x6f,
|
||||
0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e,
|
||||
0x67, 0x65, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x22, 0x42, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x6c,
|
||||
0x6c, 0x65, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a,
|
||||
0x12, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x63, 0x68, 0x61, 0x6c, 0x6c,
|
||||
0x65, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x6b, 0x0a, 0x0f,
|
||||
0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x58, 0x0a, 0x09, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x12, 0x23, 0x2e, 0x6b,
|
||||
0x6f, 0x70, 0x73, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x24, 0x2e, 0x6b, 0x6f, 0x70, 0x73, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72,
|
||||
0x61, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x25, 0x5a, 0x23, 0x6b, 0x38, 0x73,
|
||||
0x2e, 0x69, 0x6f, 0x2f, 0x6b, 0x6f, 0x70, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6b,
|
||||
0x6f, 0x70, 0x73, 0x2f, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x2f, 0x76, 0x31,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_kops_bootstrap_v1_bootstrap_proto_rawDescOnce sync.Once
|
||||
file_kops_bootstrap_v1_bootstrap_proto_rawDescData = file_kops_bootstrap_v1_bootstrap_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_kops_bootstrap_v1_bootstrap_proto_rawDescGZIP() []byte {
|
||||
file_kops_bootstrap_v1_bootstrap_proto_rawDescOnce.Do(func() {
|
||||
file_kops_bootstrap_v1_bootstrap_proto_rawDescData = protoimpl.X.CompressGZIP(file_kops_bootstrap_v1_bootstrap_proto_rawDescData)
|
||||
})
|
||||
return file_kops_bootstrap_v1_bootstrap_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_kops_bootstrap_v1_bootstrap_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_kops_bootstrap_v1_bootstrap_proto_goTypes = []interface{}{
|
||||
(*ChallengeRequest)(nil), // 0: kops.bootstrap.v1.ChallengeRequest
|
||||
(*ChallengeResponse)(nil), // 1: kops.bootstrap.v1.ChallengeResponse
|
||||
}
|
||||
var file_kops_bootstrap_v1_bootstrap_proto_depIdxs = []int32{
|
||||
0, // 0: kops.bootstrap.v1.CallbackService.Challenge:input_type -> kops.bootstrap.v1.ChallengeRequest
|
||||
1, // 1: kops.bootstrap.v1.CallbackService.Challenge:output_type -> kops.bootstrap.v1.ChallengeResponse
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_kops_bootstrap_v1_bootstrap_proto_init() }
|
||||
func file_kops_bootstrap_v1_bootstrap_proto_init() {
|
||||
if File_kops_bootstrap_v1_bootstrap_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_kops_bootstrap_v1_bootstrap_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ChallengeRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_kops_bootstrap_v1_bootstrap_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ChallengeResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_kops_bootstrap_v1_bootstrap_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_kops_bootstrap_v1_bootstrap_proto_goTypes,
|
||||
DependencyIndexes: file_kops_bootstrap_v1_bootstrap_proto_depIdxs,
|
||||
MessageInfos: file_kops_bootstrap_v1_bootstrap_proto_msgTypes,
|
||||
}.Build()
|
||||
File_kops_bootstrap_v1_bootstrap_proto = out.File
|
||||
file_kops_bootstrap_v1_bootstrap_proto_rawDesc = nil
|
||||
file_kops_bootstrap_v1_bootstrap_proto_goTypes = nil
|
||||
file_kops_bootstrap_v1_bootstrap_proto_depIdxs = nil
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package kops.bootstrap.v1;
|
||||
|
||||
option go_package = "k8s.io/kops/proto/kops/bootstrap/v1";
|
||||
|
||||
// CallbackService is the service that the node must run during bootstrapping,
|
||||
// we perform a simple callback from the controller.
|
||||
service CallbackService {
|
||||
// Answers challenges to cross-check bootstrap requests.
|
||||
rpc Challenge(ChallengeRequest) returns (ChallengeResponse) {}
|
||||
}
|
||||
|
||||
message ChallengeRequest {
|
||||
// challenge_id is a random value (nonce) that the node generated and passed in its bootstrap request.
|
||||
string challenge_id = 1;
|
||||
|
||||
// challenge_random is a random value (nonce) that kops-controller generated, it is hashed into the response.
|
||||
bytes challenge_random = 2;
|
||||
}
|
||||
|
||||
message ChallengeResponse {
|
||||
// challenge_response combines the node nonce with the kops-controller nonce.
|
||||
// The node nonce is passed in the bootstrap request.
|
||||
// The kops-controller nonce is challenge_random in the ChallengeRequest.
|
||||
// challenge_response is expected to be sha256(node-node + kops-controller-nonce)
|
||||
bytes challenge_response = 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
Copyright 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.
|
||||
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.
|
||||
*/
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
// CallbackServiceClient is the client API for CallbackService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type CallbackServiceClient interface {
|
||||
// Answers challenges to cross-check bootstrap requests.
|
||||
Challenge(ctx context.Context, in *ChallengeRequest, opts ...grpc.CallOption) (*ChallengeResponse, error)
|
||||
}
|
||||
|
||||
type callbackServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewCallbackServiceClient(cc grpc.ClientConnInterface) CallbackServiceClient {
|
||||
return &callbackServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *callbackServiceClient) Challenge(ctx context.Context, in *ChallengeRequest, opts ...grpc.CallOption) (*ChallengeResponse, error) {
|
||||
out := new(ChallengeResponse)
|
||||
err := c.cc.Invoke(ctx, "/kops.bootstrap.v1.CallbackService/Challenge", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// CallbackServiceServer is the server API for CallbackService service.
|
||||
// All implementations must embed UnimplementedCallbackServiceServer
|
||||
// for forward compatibility
|
||||
type CallbackServiceServer interface {
|
||||
// Answers challenges to cross-check bootstrap requests.
|
||||
Challenge(context.Context, *ChallengeRequest) (*ChallengeResponse, error)
|
||||
mustEmbedUnimplementedCallbackServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedCallbackServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedCallbackServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedCallbackServiceServer) Challenge(context.Context, *ChallengeRequest) (*ChallengeResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Challenge not implemented")
|
||||
}
|
||||
func (UnimplementedCallbackServiceServer) mustEmbedUnimplementedCallbackServiceServer() {}
|
||||
|
||||
// UnsafeCallbackServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to CallbackServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeCallbackServiceServer interface {
|
||||
mustEmbedUnimplementedCallbackServiceServer()
|
||||
}
|
||||
|
||||
func RegisterCallbackServiceServer(s grpc.ServiceRegistrar, srv CallbackServiceServer) {
|
||||
s.RegisterService(&CallbackService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _CallbackService_Challenge_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ChallengeRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CallbackServiceServer).Challenge(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/kops.bootstrap.v1.CallbackService/Challenge",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CallbackServiceServer).Challenge(ctx, req.(*ChallengeRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// CallbackService_ServiceDesc is the grpc.ServiceDesc for CallbackService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var CallbackService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "kops.bootstrap.v1.CallbackService",
|
||||
HandlerType: (*CallbackServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Challenge",
|
||||
Handler: _CallbackService_Challenge_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "kops/bootstrap/v1/bootstrap.proto",
|
||||
}
|
||||
|
|
@ -261,6 +261,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: additionalobjects.example.com
|
||||
ConfigBase: memfs://tests/additionalobjects.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: additionalobjects.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: apiserver
|
||||
InstanceGroupRole: APIServer
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: bastionuserdata.example.com
|
||||
ConfigBase: memfs://clusters.example.com/bastionuserdata.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: bastionuserdata.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: cas-priority-expander-custom.example.com
|
||||
ConfigBase: memfs://clusters.example.com/cas-priority-expander-custom.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: cas-priority-expander-custom.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: cas-priority-expander-custom.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: cas-priority-expander-custom.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: cas-priority-expander.example.com
|
||||
ConfigBase: memfs://clusters.example.com/cas-priority-expander.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: cas-priority-expander.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: cas-priority-expander.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: cas-priority-expander.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: complex.example.com
|
||||
ConfigBase: memfs://clusters.example.com/complex.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: complex.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ ensure-install-dir
|
|||
|
||||
echo "H4sIAAAAAAAA/+xWXW/bNhe+968g+qJ3tWQ3afpW6I1qZ4mW2PXkZNmuApo8lrlQpHZIKvF+/UBSsp00GTYMK3pRFGjM88Xz8ZyHYlI7PtFqLapsQEhNFa1gaTXSCiaSGgMmIxYdDEAx3DZWaNWZE+WkHIBlfCKdsYDGR4AWlA2/+mgYD4SsKLtzTQkWlA8zpVuTkQ+jTguq7Q2HRNEaMnJ6NZnezvJ5fnZa3k7z4vLX20/55OJ6sbwtT69O51fF53nnQkhLpQMfjwdRC2iEVhk5St4l70NpQn1zad25FeSLYgnYxoSolPp+gaIVEirgXe8JoUqrba2dyZ3dZGRNpQniRuSOC1AMQs+HxEdEBRZMYlqWcFhTJ200jddMtFM2I2Mvc3ajUfxBfeEzzSEjubynW5P7NAaErITiOecIxmRklIR/A0ICahaoW8EBMwIPFlBR6cev6EpCzmthfJ0L6SqhutTmtAbTUAaXYg1syyQE8aWohS2pqgDD2WcpGOSM+USDaBqrOMTlofxKS8BQwxKYVjwqZ85SK1S1S+YGVhut74LyZyoFf1k91xxKMBYF82GDrASjHTL4yWlLfamW8djRrr6NtY3J0nT89n3o1Dg7Ho3Gjy0/t4AoeD+tNK7L/551fTsgZA3UOoQzaqFbqsmymIkqlpvfLDPyykPkVdAV6goBYtPzm+W1QqiEX80DK1HTCjISNbhN7v5vEqFTj5shbYSJUGzHyduTMGuvkGAXCGtAhB4OV9umL6JQcfzFIhzPtbF+UcLh9OFAJ3V1CS3IjPjSEH53YOwGKAcMgAMeIBKj0qpCqKjV+NT29MEiPQ8/fVbioXf5ZVhCrS0Mg8Xwqd8ZatdEv6cOQfXU/tr41Gt43sVrB4QYYA5hodFm5Pj4KEgO8VsY43z/+wnTRiSia1jCdN34ZibwQOtGghd8EeHHm4vldVn8gxCpbkAJnrbj9Lf7O7OP2BF1sQjrlpHxaJScHHvEpeOQelywT5TdgeJZAO5RIKmJVha1lICzPXt6smLUgt+WSTEtzZ6urKVsMwX/f+l3kgkJy61iC0CheUbG9cj8JZGwmKoPG/P8cBLzHO+V80DHLzSRhVfKIUz8HaV2foN2xPl194rtujfsH5/9gskIagmBamIyB7JdTx9vjzPwmCgnCNy/YFT2Y/BXL9kGuJNxXl+3aLO7+t/V2hFQ9vIryCq/vlMUnrmI2RoLNd/JS61tRtK/g7bpfHmwFOPRgUaH74f+mHjg79+7KaxcVQlVnVPFpeeKvhBo4wtyTpFnpIZa4zahLRXS+30cj0Yz8UZpDmvzSPy6Fwr/1/yAAB/fvX4T+v2FaS99ZPufzNvPIi7WgvoJpC3FVIpV2g0p3Rt8gdhG80KtkXoqoUIBFs+Dp6HOQHaUnESfGVViDcZ2F4Jl6f4bJ607rSeTBrUFZi+8TnafBvtJ9NV0G+Gbt9OZjbNc36szpAx6ijoKDPWMaoLCCkblQnPj4WIGNfWRL74D9TtQv22g/gkAAP//AQAA///KG9Hm7w0AAA==" | base64 -d | gzip -d > conf/cluster_spec.yaml
|
||||
|
||||
echo "H4sIAAAAAAAA/1SOQWrDMBBF9zqFLuCY0LoBQTcxpDVp3WASsh7kUeJW0qgayTU+fTFZefv57/FqS7k/RRqHHqOS8MeiJm+G2x4YlXToDKuy1DZzwsgbnMAFixtNrtTkQkRejaLxnMBrfIuUQwtukcDCFpmLhJyKLaxPHVlUsiafItmTBY+ipR5zeIS8A9+VnLaX7vv2vPu5fn1eq3l3buO+q5qX+X5+Ohybg/mtRoBj/jCXV/EPAAD//wEAAP//1eFPetUAAAA=" | base64 -d | gzip -d > conf/kube_env.yaml
|
||||
echo "H4sIAAAAAAAA/2zO0UrDMBTG8fs8RV6gK0PrIODNAtMyraNs7PqQnmzTJCfmJLP06UV6VfD+/+P7tKMyHBLdbwMmJeGHhXaFM6YOPCppyMeEzCscwUeHK0NeaAr2dtkCo5IevWVV12ZWi7D+V7eBMwSDL4lKnFc8/NmqcJWRc7WGZdSTQyU1hZzIHRwEFB0NWOJ85BX4quS4PvWfl8fN1/nj/dxMm2OXtn3TPk3X48Nu3+7sd3MH2Jc3e3oWvwAAAP//AQAA///JQrb09wAAAA==" | base64 -d | gzip -d > conf/kube_env.yaml
|
||||
|
||||
download-release
|
||||
echo "== nodeup node config done =="
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ ensure-install-dir
|
|||
|
||||
echo "H4sIAAAAAAAA/2yST2/bMAzF7/4URIHeCttZt2IQeikSrA22DMGyYWfGohWishhQkrd8+0Fu3D9YT4b4e8R70nPnJdulhJ6dqQAGDOhol0TR0dJjjBQNJM1UPeY9eUpFhUHCaZAc73I6GOjRR6oAOqeSjyvlkdRAPMVEg32e/xBJBppyLp5blZFtEdLfRBrQTyTHRLr6vjOwaNv65mPd1ov2FZEBOZj5WHvppkUKuPe0on12joN7wGA96RwdgEbuEkt4QLUGBhpETzWOyL7s3S7adsNXQSz18c34ch5y+cYvSnT76fKKB3T/S+fpG20F0BOmrHSPiWJ5PoDlbr1hp1gi3f3eGbgoOS8mtg4/lWjrs+PCfgUlx+Wyr1Sli24qbYulgWZEbTzvm3NJzYugAvDivtFI3sCHCuAodh16xaWEhBxI1yW2gScbPdWPn2PN0hwxRzLX9c3TzgYD9xTT2ZBSN5looESxGc40FrFKoi59LcyvqMfs00sT82123YFsnh7vmcVDTlb+hHvFjrakLNbAdRvfR0vlxB36rdhYfpdY/QMAAP//AQAA//+ifSCJzQIAAA==" | base64 -d | gzip -d > conf/cluster_spec.yaml
|
||||
|
||||
echo "H4sIAAAAAAAA/6yUS4+qSBiG9/4K9ua0iIpg0ouP4mJhgyC3Q+8QAUEuxUVLzfz4ifQkJ5M5mUwmzYLF+6aexZcnLyqb68nqmlt+SroNE9F+gpo6zTMn6W5Jt5kwDAKUdEOe5nE0JP2G+WPCMAzz4/VJioZNBikHF6sYgauM6dgbGEvHAiE45BlQLEGGDZWA2UqyYDqywIHnGMBqyGk1Bx8Xsq1IiHpgSNldLcAbIVJm+hIYrhwM87DyH8fKZz9/GkPIKXR7jk2jUKj5hIUhx3QvAw1e2fNXNkLGooDQOIRUhVD2bVtW6Lw7BXoZV6vypPnPj8A8Gyqlsh3qu+YTn2+xCbYiSTbII8ShQB3QJTBVvHh2rHsRLl0fCDdapAZ56vsysAV+zt+0RWhFXAsZXvvLZkdTn33gbD5CimG65dOlNaMXCyzXctMDEfFDaLaKolIWAVUAIhMZClA5C2X/wFpgb2cS2DJkivZ1WBA0mHsnhSrSjNqqAYYEqUC39vhgL0mhopra4ukXbvxR6lTu9eVsJ8r+etecPfgL8s/LA6uAJJzYRRpydB3sSLrnxBZz4opcObSMIxFyX9uTzImFETJUdt/yXXwfFu60O64E0fKHJ1vRWbxz7/sLn205hND0sU0fHH1//+WNYsq/t+b/WnWrnIjdQxlWP3ffa5VrcL+36lV8m1WGyqvL6PNEEvbgkcfjEkkkoJ+opsc0PYfank7Tnj+cPq5eu7aRWenVTGnXIyQI9s/cCOUci84xLok85e1cZ82F0hLie99o1QeuCA+HwpJhy9dnPO3jwB8Wtnis/9Uq3/bvK8MbroCTxLpaYrOa3wficg6v3tJc0JcY3evyS01RWnsyd+3Psa9aQ5Q0H6KWXoUoXO50KWnbbNUU5bKtDrV7Lv6LVf24ZP1ryn4w52Eg/WY2uzSk/xE39dA1ZZl0b3k9JF0dlW9xU5Eu6fu35B5VpExewWYhCsJsgut+iOo40brmSsyoSjZM3ZyS/u/FoSmTDWM2p2Ty+l3J155uo/68YYDtLp7x5BCHh2CuGR2fcmhNYrFIPU61+zYA3Xvq2xrw++RPAAAA//8BAAD//zgmNPacBQAA" | base64 -d | gzip -d > conf/kube_env.yaml
|
||||
echo "H4sIAAAAAAAA/6yUS4+ySBiF9/4K9qZbREUw6cVLcbGwQZDbR+8QAUEuxUVLzfz4SdOTfJlMZzKZNAsW56SexZsnB5XN9WR1zS0/Jd2GiWg/QeW1H5LOjKpkw8RNRbqk71+Te1SRMnmNm2qCmjrNMyfpbkm3mTAMApR0Q57mcTQk/Yb5Y8IwDPPy+UmKhk0GKQcXqxiBq4zp2BsYS8cCITjkGVAsQYYNlYDZSrJgOrLAgecYwGrIaTUHHxeyrUiIemBI2V0twBshUmb6EhiuHAzzsPIfx8pnP34ZQ8gpdHuOTaNQqPmEhSHHdC8DDT6z5+9shIxFAaFxCKkKoezbtqzQeXcK9DKuVuVJ85/vgXk2VEplO9R3zQc+32ITbEWSbJBHiEOBOqBLYKp48exY9yJcuj4QbrRIDfLU92VgC/ycv2mL0Iq4FjK89pfNjqY++8DZfIQUw3TLp0trRi8WWK7lpgci4ofQbBVFpSwCqgBEJjIUoHIWyv6BtcDeziSwZcgU7euwIGgw904KVaQZtVUDDAlSgW7t8cFekkJFNbXF0y/c+L3Uqdzry9lOlP31rjl78Bfkn5cHVgFJOLGLNOToOtiRdM+JLebEFblyaBlHIuS+tieZEwsjZKjsvuW7+D4s3Gl3XAmi5Q9PtqKzeOfe9xc+23IIoeljmz44+vb22xvFlL+35v9adauciN1DGVa/dj9rlWtw31v1WfyYVYbKq8vo40QS9uCRx+MSSSSgH6imxzQ9h9qeTtOeP5zer167tpFZ6dVMadcjJAj2z9wI5RyLzjEuiTzl7VxnzYXSEuJ7P2jVO64ID4fCkmHL12c87ePAHxa2eKz/1Srf9u8rwxuugJPEulpis5rfB+JyDq/e0lzQlxjd6/JLTVFaezJ37c+xr1pDlDTvopZehShc7nQpadts1RTlsq0OtXsu/otV/bhk/eeUvTDnYSD9Zja7NKR/iZt66JqyTLrXvB6Sro7K1+8mcbMQBWE2wXU/RHWcaF1zJV8DWjenpP97cWjKZMOYzSmZfP6u5GtPt1F/3jDAdhfPeHKIw0Mw14yOTzm0JrFYpB6n2n0bgO499W0N+G3yJwAAAP//AQAA//8syA67vgUAAA==" | base64 -d | gzip -d > conf/kube_env.yaml
|
||||
|
||||
download-release
|
||||
echo "== nodeup node config done =="
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: containerd.example.com
|
||||
ConfigBase: memfs://clusters.example.com/containerd.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: containerd.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: containerd.example.com
|
||||
ConfigBase: memfs://clusters.example.com/containerd.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: containerd.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: 123.example.com
|
||||
ConfigBase: memfs://clusters.example.com/123.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: 123.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -257,6 +257,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: docker.example.com
|
||||
ConfigBase: memfs://clusters.example.com/docker.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: docker.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: existing-iam.example.com
|
||||
ConfigBase: memfs://tests/existing-iam.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: existing-iam.example.com
|
||||
ConfigBase: memfs://tests/existing-iam.example.com
|
||||
InstanceGroupName: master-us-test-1b
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: existing-iam.example.com
|
||||
ConfigBase: memfs://tests/existing-iam.example.com
|
||||
InstanceGroupName: master-us-test-1c
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: existing-iam.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: existingsg.example.com
|
||||
ConfigBase: memfs://clusters.example.com/existingsg.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: existingsg.example.com
|
||||
ConfigBase: memfs://clusters.example.com/existingsg.example.com
|
||||
InstanceGroupName: master-us-test-1b
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: existingsg.example.com
|
||||
ConfigBase: memfs://clusters.example.com/existingsg.example.com
|
||||
InstanceGroupName: master-us-test-1c
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: existingsg.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: externallb.example.com
|
||||
ConfigBase: memfs://clusters.example.com/externallb.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: externallb.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: externalpolicies.example.com
|
||||
ConfigBase: memfs://clusters.example.com/externalpolicies.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: externalpolicies.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: ha.example.com
|
||||
ConfigBase: memfs://tests/ha.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: ha.example.com
|
||||
ConfigBase: memfs://tests/ha.example.com
|
||||
InstanceGroupName: master-us-test-1b
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: ha.example.com
|
||||
ConfigBase: memfs://tests/ha.example.com
|
||||
InstanceGroupName: master-us-test-1c
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: ha.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: gce
|
||||
ClusterName: ha-gce.example.com
|
||||
ConfigBase: memfs://tests/ha-gce.example.com
|
||||
InstanceGroupName: master-us-test1-a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: gce
|
||||
ClusterName: ha-gce.example.com
|
||||
ConfigBase: memfs://tests/ha-gce.example.com
|
||||
InstanceGroupName: master-us-test1-b
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: gce
|
||||
ClusterName: ha-gce.example.com
|
||||
ConfigBase: memfs://tests/ha-gce.example.com
|
||||
InstanceGroupName: master-us-test1-c
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: gce
|
||||
ClusterName: ha-gce.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -255,6 +255,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -257,6 +257,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -255,6 +255,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -255,6 +255,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -255,6 +255,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -255,6 +255,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -245,6 +245,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: gce
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://tests/minimal.example.com
|
||||
InstanceGroupName: master-us-test1-a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: gce
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -255,6 +255,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigBase: memfs://clusters.example.com/minimal.example.com
|
||||
InstanceGroupName: master-us-test-1a
|
||||
InstanceGroupRole: ControlPlane
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ __EOF_CLUSTER_SPEC
|
|||
|
||||
cat > conf/kube_env.yaml << '__EOF_KUBE_ENV'
|
||||
CloudProvider: aws
|
||||
ClusterName: minimal.example.com
|
||||
ConfigServer:
|
||||
CACertificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue