mirror of https://github.com/kubernetes/kops.git
Seed the random number generator on AWS
This commit is contained in:
parent
7ec956dd00
commit
42bf3ee85b
|
|
@ -43,11 +43,7 @@ func (b BootstrapClientBuilder) Build(c *fi.ModelBuilderContext) error {
|
||||||
var err error
|
var err error
|
||||||
switch kops.CloudProviderID(b.Cluster.Spec.CloudProvider) {
|
switch kops.CloudProviderID(b.Cluster.Spec.CloudProvider) {
|
||||||
case kops.CloudProviderAWS:
|
case kops.CloudProviderAWS:
|
||||||
region, regionErr := awsup.FindRegion(b.Cluster)
|
authenticator, err = awsup.NewAWSAuthenticator(b.Cloud.Region())
|
||||||
if regionErr != nil {
|
|
||||||
return fmt.Errorf("querying AWS region: %v", regionErr)
|
|
||||||
}
|
|
||||||
authenticator, err = awsup.NewAWSAuthenticator(region)
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported cloud provider %s", b.Cluster.Spec.CloudProvider)
|
return fmt.Errorf("unsupported cloud provider %s", b.Cluster.Spec.CloudProvider)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ type Config struct {
|
||||||
InstanceGroupRole kops.InstanceGroupRole
|
InstanceGroupRole kops.InstanceGroupRole
|
||||||
// ClusterName is the name of the cluster
|
// ClusterName is the name of the cluster
|
||||||
ClusterName string `json:",omitempty"`
|
ClusterName string `json:",omitempty"`
|
||||||
|
// CloudProvider is the cloud provider in use.
|
||||||
|
CloudProvider string
|
||||||
// Channels is a list of channels that we should apply
|
// Channels is a list of channels that we should apply
|
||||||
Channels []string `json:"channels,omitempty"`
|
Channels []string `json:"channels,omitempty"`
|
||||||
// ApiserverAdditionalIPs are additional IP address to put in the apiserver server cert.
|
// ApiserverAdditionalIPs are additional IP address to put in the apiserver server cert.
|
||||||
|
|
@ -91,9 +93,6 @@ type ConfigServerOptions struct {
|
||||||
Server string `json:"server,omitempty"`
|
Server string `json:"server,omitempty"`
|
||||||
// CA is the ca-certificate to require for the configuration server
|
// CA is the ca-certificate to require for the configuration server
|
||||||
CA string `json:"ca,omitempty"`
|
CA string `json:"ca,omitempty"`
|
||||||
|
|
||||||
// CloudProvider is the cloud provider in use (needed for authentication)
|
|
||||||
CloudProvider string `json:"cloudProvider,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image is a docker image we should pre-load
|
// Image is a docker image we should pre-load
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,7 @@ func (r *NodeRoleAPIServer) BuildAWSPolicy(b *PolicyBuilder) (*Policy, error) {
|
||||||
addMasterEC2Policies(p, resource, b.Cluster.GetName())
|
addMasterEC2Policies(p, resource, b.Cluster.GetName())
|
||||||
addASLifecyclePolicies(p, resource, b.Cluster.GetName(), r.warmPool)
|
addASLifecyclePolicies(p, resource, b.Cluster.GetName(), r.warmPool)
|
||||||
addCertIAMPolicies(p, resource)
|
addCertIAMPolicies(p, resource)
|
||||||
|
addKMSGenerateRandomPolicies(p)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if p, err = b.AddS3Permissions(p); err != nil {
|
if p, err = b.AddS3Permissions(p); err != nil {
|
||||||
|
|
@ -293,6 +294,7 @@ func (r *NodeRoleMaster) BuildAWSPolicy(b *PolicyBuilder) (*Policy, error) {
|
||||||
addMasterASPolicies(p, resource, b.Cluster.GetName())
|
addMasterASPolicies(p, resource, b.Cluster.GetName())
|
||||||
addMasterELBPolicies(p, resource)
|
addMasterELBPolicies(p, resource)
|
||||||
addCertIAMPolicies(p, resource)
|
addCertIAMPolicies(p, resource)
|
||||||
|
addKMSGenerateRandomPolicies(p)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if p, err = b.AddS3Permissions(p); err != nil {
|
if p, err = b.AddS3Permissions(p); err != nil {
|
||||||
|
|
@ -354,6 +356,7 @@ func (r *NodeRoleNode) BuildAWSPolicy(b *PolicyBuilder) (*Policy, error) {
|
||||||
|
|
||||||
addNodeEC2Policies(p, resource)
|
addNodeEC2Policies(p, resource)
|
||||||
addASLifecyclePolicies(p, resource, b.Cluster.GetName(), r.enableLifecycleHookPermissions)
|
addASLifecyclePolicies(p, resource, b.Cluster.GetName(), r.enableLifecycleHookPermissions)
|
||||||
|
addKMSGenerateRandomPolicies(p)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if p, err = b.AddS3Permissions(p); err != nil {
|
if p, err = b.AddS3Permissions(p); err != nil {
|
||||||
|
|
@ -866,6 +869,17 @@ func addKMSIAMPolicies(p *Policy, resource stringorslice.StringOrSlice) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addKMSGenerateRandomPolicies(p *Policy) {
|
||||||
|
// For nodeup to seed the instance's random number generator.
|
||||||
|
p.Statement = append(p.Statement, &Statement{
|
||||||
|
Effect: StatementEffectAllow,
|
||||||
|
Action: stringorslice.Of(
|
||||||
|
"kms:GenerateRandom",
|
||||||
|
),
|
||||||
|
Resource: stringorslice.Slice([]string{"*"}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func addNodeEC2Policies(p *Policy, resource stringorslice.StringOrSlice) {
|
func addNodeEC2Policies(p *Policy, resource stringorslice.StringOrSlice) {
|
||||||
// Protokube makes a DescribeInstances call, DescribeRegions when finding S3 State Bucket
|
// Protokube makes a DescribeInstances call, DescribeRegions when finding S3 State Bucket
|
||||||
p.Statement = append(p.Statement, &Statement{
|
p.Statement = append(p.Statement, &Statement{
|
||||||
|
|
|
||||||
|
|
@ -1319,6 +1319,7 @@ func (n *nodeUpConfigBuilder) BuildConfig(ig *kops.InstanceGroup, apiserverAddit
|
||||||
}
|
}
|
||||||
config.ClusterName = cluster.ObjectMeta.Name
|
config.ClusterName = cluster.ObjectMeta.Name
|
||||||
config.InstanceGroupName = ig.ObjectMeta.Name
|
config.InstanceGroupName = ig.ObjectMeta.Name
|
||||||
|
config.CloudProvider = cluster.Spec.CloudProvider
|
||||||
|
|
||||||
if isMaster || useGossip {
|
if isMaster || useGossip {
|
||||||
for _, arch := range architectures.GetSupported() {
|
for _, arch := range architectures.GetSupported() {
|
||||||
|
|
@ -1349,9 +1350,8 @@ func (n *nodeUpConfigBuilder) BuildConfig(ig *kops.InstanceGroup, apiserverAddit
|
||||||
}
|
}
|
||||||
|
|
||||||
configServer := &nodeup.ConfigServerOptions{
|
configServer := &nodeup.ConfigServerOptions{
|
||||||
Server: baseURL.String(),
|
Server: baseURL.String(),
|
||||||
CloudProvider: cluster.Spec.CloudProvider,
|
CA: ca,
|
||||||
CA: ca,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config.ConfigServer = configServer
|
config.ConfigServer = configServer
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ go_library(
|
||||||
"//vendor/github.com/aws/aws-sdk-go/aws/session:go_default_library",
|
"//vendor/github.com/aws/aws-sdk-go/aws/session:go_default_library",
|
||||||
"//vendor/github.com/aws/aws-sdk-go/service/autoscaling:go_default_library",
|
"//vendor/github.com/aws/aws-sdk-go/service/autoscaling:go_default_library",
|
||||||
"//vendor/github.com/aws/aws-sdk-go/service/ec2:go_default_library",
|
"//vendor/github.com/aws/aws-sdk-go/service/ec2:go_default_library",
|
||||||
|
"//vendor/github.com/aws/aws-sdk-go/service/kms:go_default_library",
|
||||||
"//vendor/k8s.io/klog/v2:go_default_library",
|
"//vendor/k8s.io/klog/v2:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,13 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/service/kms"
|
||||||
"k8s.io/kops/nodeup/pkg/model"
|
"k8s.io/kops/nodeup/pkg/model"
|
||||||
"k8s.io/kops/nodeup/pkg/model/networking"
|
"k8s.io/kops/nodeup/pkg/model/networking"
|
||||||
api "k8s.io/kops/pkg/apis/kops"
|
api "k8s.io/kops/pkg/apis/kops"
|
||||||
|
|
@ -91,13 +93,21 @@ func (c *NodeUpCommand) Run(out io.Writer) error {
|
||||||
return fmt.Errorf("CacheDir is required")
|
return fmt.Errorf("CacheDir is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
region, err := getRegion(ctx, c.config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = seedRNG(ctx, c.config, region); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var configBase vfs.Path
|
var configBase vfs.Path
|
||||||
|
|
||||||
// If we're using a config server instead of vfs, nodeConfig will hold our configuration
|
// If we're using a config server instead of vfs, nodeConfig will hold our configuration
|
||||||
var nodeConfig *nodeup.NodeConfig
|
var nodeConfig *nodeup.NodeConfig
|
||||||
|
|
||||||
if c.config.ConfigServer != nil {
|
if c.config.ConfigServer != nil {
|
||||||
response, err := getNodeConfigFromServer(ctx, c.config.ConfigServer)
|
response, err := getNodeConfigFromServer(ctx, c.config, region)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -182,7 +192,7 @@ func (c *NodeUpCommand) Run(out io.Writer) error {
|
||||||
return fmt.Errorf("auxiliary config hash mismatch")
|
return fmt.Errorf("auxiliary config hash mismatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := evaluateSpec(c)
|
err = evaluateSpec(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -209,10 +219,6 @@ func (c *NodeUpCommand) Run(out io.Writer) error {
|
||||||
var cloud fi.Cloud
|
var cloud fi.Cloud
|
||||||
|
|
||||||
if api.CloudProviderID(c.cluster.Spec.CloudProvider) == api.CloudProviderAWS {
|
if api.CloudProviderID(c.cluster.Spec.CloudProvider) == api.CloudProviderAWS {
|
||||||
region, err := awsup.FindRegion(c.cluster)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
awsCloud, err := awsup.NewAWSCloud(region, nil)
|
awsCloud, err := awsup.NewAWSCloud(region, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -674,16 +680,60 @@ func loadKernelModules(context *model.NodeupModelContext) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getNodeConfigFromServer queries kops-controller for our node's configuration.
|
// getRegionAndSeedRNG queries the cloud provider for the region and adds entropy to the random number generator.
|
||||||
func getNodeConfigFromServer(ctx context.Context, config *nodeup.ConfigServerOptions) (*nodeup.BootstrapResponse, error) {
|
func getRegion(ctx context.Context, config *nodeup.Config) (string, error) {
|
||||||
var authenticator fi.Authenticator
|
|
||||||
|
|
||||||
switch api.CloudProviderID(config.CloudProvider) {
|
switch api.CloudProviderID(config.CloudProvider) {
|
||||||
case api.CloudProviderAWS:
|
case api.CloudProviderAWS:
|
||||||
region, err := awsup.RegionFromMetadata(ctx)
|
region, err := awsup.RegionFromMetadata(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return region, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// seedRNG adds entropy to the random number generator.
|
||||||
|
func seedRNG(ctx context.Context, config *nodeup.Config, region string) error {
|
||||||
|
switch api.CloudProviderID(config.CloudProvider) {
|
||||||
|
case api.CloudProviderAWS:
|
||||||
|
config := aws.NewConfig().WithCredentialsChainVerboseErrors(true).WithRegion(region)
|
||||||
|
sess, err := session.NewSession(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
random, err := kms.New(sess, config).GenerateRandom(&kms.GenerateRandomInput{
|
||||||
|
NumberOfBytes: aws.Int64(64),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("generating random seed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.OpenFile("/dev/urandom", os.O_WRONLY, 0)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("opening /dev/urandom: %v", err)
|
||||||
|
}
|
||||||
|
_, err = f.Write(random.Plaintext)
|
||||||
|
if err1 := f.Close(); err1 != nil && err == nil {
|
||||||
|
err = err1
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("writing /dev/urandom: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getNodeConfigFromServer queries kops-controller for our node's configuration.
|
||||||
|
func getNodeConfigFromServer(ctx context.Context, config *nodeup.Config, region string) (*nodeup.BootstrapResponse, error) {
|
||||||
|
var authenticator fi.Authenticator
|
||||||
|
|
||||||
|
switch api.CloudProviderID(config.CloudProvider) {
|
||||||
|
case api.CloudProviderAWS:
|
||||||
a, err := awsup.NewAWSAuthenticator(region)
|
a, err := awsup.NewAWSAuthenticator(region)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -697,13 +747,13 @@ func getNodeConfigFromServer(ctx context.Context, config *nodeup.ConfigServerOpt
|
||||||
Authenticator: authenticator,
|
Authenticator: authenticator,
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.CA != "" {
|
if config.ConfigServer.CA != "" {
|
||||||
client.CA = []byte(config.CA)
|
client.CA = []byte(config.ConfigServer.CA)
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.Parse(config.Server)
|
u, err := url.Parse(config.ConfigServer.Server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to parse configuration server url %q: %w", config.Server, err)
|
return nil, fmt.Errorf("unable to parse configuration server url %q: %w", config.ConfigServer.Server, err)
|
||||||
}
|
}
|
||||||
client.BaseURL = *u
|
client.BaseURL = *u
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue