mirror of https://github.com/kubernetes/kops.git
parent
aa190b8c3f
commit
302f23463e
|
@ -36,6 +36,7 @@ type CreateClusterCmd struct {
|
||||||
VPCID string
|
VPCID string
|
||||||
NetworkCIDR string
|
NetworkCIDR string
|
||||||
DNSZone string
|
DNSZone string
|
||||||
|
AdminAccess string
|
||||||
}
|
}
|
||||||
|
|
||||||
var createCluster CreateClusterCmd
|
var createCluster CreateClusterCmd
|
||||||
|
@ -93,6 +94,7 @@ func init() {
|
||||||
|
|
||||||
cmd.Flags().StringVar(&createCluster.DNSZone, "dns-zone", "", "DNS hosted zone to use (defaults to last two components of cluster name)")
|
cmd.Flags().StringVar(&createCluster.DNSZone, "dns-zone", "", "DNS hosted zone to use (defaults to last two components of cluster name)")
|
||||||
cmd.Flags().StringVar(&createCluster.OutDir, "out", "", "Path to write any local output")
|
cmd.Flags().StringVar(&createCluster.OutDir, "out", "", "Path to write any local output")
|
||||||
|
cmd.Flags().StringVar(&createCluster.AdminAccess, "admin-access", "", "Restrict access to admin endpoints (SSH, HTTPS) to this CIDR. If not set, access will not be restricted by IP.")
|
||||||
}
|
}
|
||||||
|
|
||||||
var EtcdClusters = []string{"main", "events"}
|
var EtcdClusters = []string{"main", "events"}
|
||||||
|
@ -332,6 +334,10 @@ func (c *CreateClusterCmd) Run() error {
|
||||||
c.SSHPublicKey = utils.ExpandPath(c.SSHPublicKey)
|
c.SSHPublicKey = utils.ExpandPath(c.SSHPublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.AdminAccess != "" {
|
||||||
|
cluster.Spec.AdminAccess = []string{c.AdminAccess}
|
||||||
|
}
|
||||||
|
|
||||||
err = cluster.PerformAssignments()
|
err = cluster.PerformAssignments()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error populating configuration: %v", err)
|
return fmt.Errorf("error populating configuration: %v", err)
|
||||||
|
|
|
@ -1,8 +1,24 @@
|
||||||
# Detailed description of arguments
|
# Detailed description of arguments
|
||||||
|
|
||||||
|
## admin-access
|
||||||
|
|
||||||
|
`admin-access` controls the CIDR which can access the admin endpoints (SSH to each node, HTTPS to the master).
|
||||||
|
|
||||||
|
It maps to `Cluster.Spec.AdminAccess`
|
||||||
|
|
||||||
|
If not specified, no IP level restrictions will apply (though there are still restrictions, for example you need
|
||||||
|
a permitted SSH key to access the SSH service!).
|
||||||
|
|
||||||
|
Currently this can only be a single CIDR.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
`--admin-access=18.0.0.0/8` to restrict to IPs in the 18.0.0.0/8 CIDR
|
||||||
|
|
||||||
|
|
||||||
## dns-zone
|
## dns-zone
|
||||||
|
|
||||||
dns-zone controls the Route53 hosted zone in which DNS records will be created. It can either by the name
|
`dns-zone` controls the Route53 hosted zone in which DNS records will be created. It can either by the name
|
||||||
of the hosted zone (`example.com`), or it can be the ID of the hosted zone (`Z1GABCD1ABC2DEF`)
|
of the hosted zone (`example.com`), or it can be the ID of the hosted zone (`Z1GABCD1ABC2DEF`)
|
||||||
|
|
||||||
Suppose you're creating a cluster named "dev.kubernetes.example.com`:
|
Suppose you're creating a cluster named "dev.kubernetes.example.com`:
|
||||||
|
@ -17,3 +33,7 @@ If you don't specify a dns-zone, kops will list all your hosted zones, and choos
|
||||||
is a a suffix of your cluster name. So for `dev.kubernetes.example.com`, if you have `kubernetes.example.com`,
|
is a a suffix of your cluster name. So for `dev.kubernetes.example.com`, if you have `kubernetes.example.com`,
|
||||||
`example.com` and `somethingelse.example.com`, it would choose `kubernetes.example.com`. `example.com` matches
|
`example.com` and `somethingelse.example.com`, it would choose `kubernetes.example.com`. `example.com` matches
|
||||||
but is shorter; `somethingelse.example.com` is not a suffix-match.
|
but is shorter; `somethingelse.example.com` is not a suffix-match.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
`--dns-zone=example.com` to use the hosted zone with a name of example.com
|
||||||
|
|
|
@ -35,7 +35,7 @@ securityGroupRule/egress-api-lb:
|
||||||
# HTTPS to the master ELB is allowed (for API access)
|
# HTTPS to the master ELB is allowed (for API access)
|
||||||
securityGroupRule/https-external-to-api:
|
securityGroupRule/https-external-to-api:
|
||||||
securityGroup: securityGroup/api.{{ ClusterName }}
|
securityGroup: securityGroup/api.{{ ClusterName }}
|
||||||
cidr: 0.0.0.0/0
|
cidr: {{ AdminCIDR }}
|
||||||
protocol: tcp
|
protocol: tcp
|
||||||
fromPort: 443
|
fromPort: 443
|
||||||
toPort: 443
|
toPort: 443
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
# HTTPS to the master is allowed (for API access)
|
# HTTPS to the master is allowed (for API access)
|
||||||
securityGroupRule/https-external-to-master:
|
securityGroupRule/https-external-to-master:
|
||||||
securityGroup: securityGroup/masters.{{ ClusterName }}
|
securityGroup: securityGroup/masters.{{ ClusterName }}
|
||||||
cidr: 0.0.0.0/0
|
cidr: {{ AdminCIDR }}
|
||||||
protocol: tcp
|
protocol: tcp
|
||||||
fromPort: 443
|
fromPort: 443
|
||||||
toPort: 443
|
toPort: 443
|
||||||
|
|
|
@ -24,10 +24,10 @@ securityGroupRule/master-egress:
|
||||||
egress: true
|
egress: true
|
||||||
cidr: 0.0.0.0/0
|
cidr: 0.0.0.0/0
|
||||||
|
|
||||||
# SSH is open to the world
|
# SSH is open to AdminCIDR
|
||||||
securityGroupRule/ssh-external-to-master:
|
securityGroupRule/ssh-external-to-master:
|
||||||
securityGroup: securityGroup/masters.{{ ClusterName }}
|
securityGroup: securityGroup/masters.{{ ClusterName }}
|
||||||
cidr: 0.0.0.0/0
|
cidr: {{ AdminCIDR }}
|
||||||
protocol: tcp
|
protocol: tcp
|
||||||
fromPort: 22
|
fromPort: 22
|
||||||
toPort: 22
|
toPort: 22
|
||||||
|
|
|
@ -27,7 +27,7 @@ securityGroupRule/node-egress:
|
||||||
# SSH is open to the world
|
# SSH is open to the world
|
||||||
securityGroupRule/ssh-external-to-node:
|
securityGroupRule/ssh-external-to-node:
|
||||||
securityGroup: securityGroup/nodes.{{ ClusterName }}
|
securityGroup: securityGroup/nodes.{{ ClusterName }}
|
||||||
cidr: 0.0.0.0/0
|
cidr: {{ AdminCIDR }}
|
||||||
protocol: tcp
|
protocol: tcp
|
||||||
fromPort: 22
|
fromPort: 22
|
||||||
toPort: 22
|
toPort: 22
|
||||||
|
|
|
@ -6,9 +6,9 @@ persistentDisk/kubernetes-master-{{ ClusterName }}:
|
||||||
volumeType: {{ or .MasterVolumeType "pd-ssd" }}
|
volumeType: {{ or .MasterVolumeType "pd-ssd" }}
|
||||||
|
|
||||||
# Open master HTTPS
|
# Open master HTTPS
|
||||||
firewallRule/kubernetes-master-https-{{ ClusterName }}:
|
firewallRule/kubernetes-master-https-{{ ClusterName }}-{{ AdminCIDR }}:
|
||||||
network: network/default
|
network: network/default
|
||||||
sourceRanges: 0.0.0.0/0
|
sourceRanges: {{ AdminCIDR }}
|
||||||
targetTags: {{ .MasterTag }}
|
targetTags: {{ .MasterTag }}
|
||||||
allowed: tcp:443
|
allowed: tcp:443
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ firewallRule/{{ $networkName }}-default-internal:
|
||||||
- icmp
|
- icmp
|
||||||
|
|
||||||
# SSH is open to the world
|
# SSH is open to the world
|
||||||
firewallRule/{{ $networkName }}-default-ssh:
|
firewallRule/{{ $networkName }}-default-ssh-{{ AdminCIDR }}:
|
||||||
network: network/default
|
network: network/default
|
||||||
sourceRanges: 0.0.0.0/0
|
sourceRanges: {{ AdminCIDR }}
|
||||||
allowed: tcp:22
|
allowed: tcp:22
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,10 @@ type ClusterSpec struct {
|
||||||
// It cannot overlap ServiceClusterIPRange
|
// It cannot overlap ServiceClusterIPRange
|
||||||
NonMasqueradeCIDR string `json:"nonMasqueradeCIDR,omitempty"`
|
NonMasqueradeCIDR string `json:"nonMasqueradeCIDR,omitempty"`
|
||||||
|
|
||||||
|
// AdminAccess determines the permitted access to the admin endpoints (SSH & master HTTPS)
|
||||||
|
// Currently only a single CIDR is supported (though a richer grammar could be added in future)
|
||||||
|
AdminAccess []string `json:"adminAccess,omitempty"`
|
||||||
|
|
||||||
//NetworkProvider string `json:",omitempty"`
|
//NetworkProvider string `json:",omitempty"`
|
||||||
//
|
//
|
||||||
//HairpinMode string `json:",omitempty"`
|
//HairpinMode string `json:",omitempty"`
|
||||||
|
@ -273,6 +277,17 @@ func (c *Cluster) PerformAssignments() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FillDefaults populates default values.
|
||||||
|
// This is different from PerformAssignments, because these values are changeable, and thus we don't need to
|
||||||
|
// store them (i.e. we don't need to 'lock them')
|
||||||
|
func (c *Cluster) FillDefaults() error {
|
||||||
|
if len(c.Spec.AdminAccess) == 0 {
|
||||||
|
c.Spec.AdminAccess = append(c.Spec.AdminAccess, "0.0.0.0/0")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (z *ClusterZoneSpec) performAssignments(c *Cluster) error {
|
func (z *ClusterZoneSpec) performAssignments(c *Cluster) error {
|
||||||
if z.CIDR == "" {
|
if z.CIDR == "" {
|
||||||
cidr, err := z.assignCIDR(c)
|
cidr, err := z.assignCIDR(c)
|
||||||
|
|
|
@ -178,6 +178,17 @@ func (c *Cluster) Validate(strict bool) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strict && len(c.Spec.AdminAccess) == 0 {
|
||||||
|
return fmt.Errorf("AdminAccess not configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, adminAccess := range c.Spec.AdminAccess {
|
||||||
|
_, _, err := net.ParseCIDR(adminAccess)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("AdminAccess rule %q could not be parsed (invalid CIDR)", adminAccess)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,11 @@ func (c *CreateClusterCmd) Run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = cluster.FillDefaults()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Check that instance groups are defined in valid zones
|
// Check that instance groups are defined in valid zones
|
||||||
{
|
{
|
||||||
clusterZones := make(map[string]*api.ClusterZoneSpec)
|
clusterZones := make(map[string]*api.ClusterZoneSpec)
|
||||||
|
|
|
@ -51,6 +51,7 @@ func (tf *TemplateFunctions) AddTo(dest template.FuncMap) {
|
||||||
dest["EtcdClusterMemberTags"] = tf.EtcdClusterMemberTags
|
dest["EtcdClusterMemberTags"] = tf.EtcdClusterMemberTags
|
||||||
dest["SharedVPC"] = tf.SharedVPC
|
dest["SharedVPC"] = tf.SharedVPC
|
||||||
dest["WellKnownServiceIP"] = tf.WellKnownServiceIP
|
dest["WellKnownServiceIP"] = tf.WellKnownServiceIP
|
||||||
|
dest["AdminCIDR"] = tf.AdminCIDR
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tf *TemplateFunctions) EtcdClusterMemberTags(etcd *api.EtcdClusterSpec, m *api.EtcdMemberSpec) map[string]string {
|
func (tf *TemplateFunctions) EtcdClusterMemberTags(etcd *api.EtcdClusterSpec, m *api.EtcdMemberSpec) map[string]string {
|
||||||
|
@ -77,3 +78,14 @@ func (tf *TemplateFunctions) EtcdClusterMemberTags(etcd *api.EtcdClusterSpec, m
|
||||||
func (tf *TemplateFunctions) SharedVPC() bool {
|
func (tf *TemplateFunctions) SharedVPC() bool {
|
||||||
return tf.cluster.Spec.NetworkID != ""
|
return tf.cluster.Spec.NetworkID != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AdminCIDR returns the single CIDR that is allowed access to the admin ports of the cluster (22, 443 on master)
|
||||||
|
func (tf *TemplateFunctions) AdminCIDR() (string, error) {
|
||||||
|
if len(tf.cluster.Spec.AdminAccess) == 0 {
|
||||||
|
return "0.0.0.0/0", nil
|
||||||
|
}
|
||||||
|
if len(tf.cluster.Spec.AdminAccess) == 1 {
|
||||||
|
return tf.cluster.Spec.AdminAccess[0], nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("Multiple AdminAccess rules are not (currently) supported")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue