Skip to content
This repository was archived by the owner on Jan 9, 2023. It is now read-only.

Commit dccb1b7

Browse files
authored
Merge pull request #276 from MattiasGees/198-admin-cidr
Secure endpoints to only allow certain cidr blocks
2 parents 98d9c1a + 06b43b1 commit dccb1b7

File tree

18 files changed

+175
-20
lines changed

18 files changed

+175
-20
lines changed

docs/spelling_wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Jenkins
6565
prepended
6666
username
6767
loopback
68+
CIDR
6869
addons
6970
autoscaler
7071
prometheus

docs/user-guide.rst

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,67 @@ configuration like that:
413413
enabled: true
414414
externalScrapeTargetsOnly: true
415415
416+
Secure public endpoints
417+
~~~~~~~~~~~~~~~~~~~~~~~
418+
419+
Public endpoints (Jenkins, bastion host and if enabled apiserver) can be secured
420+
by limiting the access to a list of CIDR blocks. This can be configured on a
421+
environment level for all public endpoint and if wanted can be overwritten on a
422+
specific public endpoint.
423+
424+
Environment level
425+
+++++++++++++++++
426+
427+
This can be done by adding an ``adminCIDRs`` list to an environments block,
428+
if nothing has been set, the default is 0.0.0.0/0:
429+
430+
.. code-block:: yaml
431+
432+
environments:
433+
- contact: hello@example.com
434+
location: eu-west-1
435+
metadata:
436+
name: example
437+
privateZone: example.local
438+
project: example-project
439+
provider: aws
440+
adminCIDRs:
441+
- x.x.x.x/32
442+
- y.y.y.y/24
443+
444+
Jenkins and bastion host
445+
++++++++++++++++++++++++
446+
447+
The environment level can be overwritten for Jenkins and bastion host
448+
by adding ``allowCIDRs`` in the instance pool block:
449+
450+
.. code-block:: yaml
451+
452+
instancePools:
453+
- image: centos-puppet-agent
454+
allowCIDRs:
455+
- x.x.x.x/32
456+
maxCount: 1
457+
metadata:
458+
name: jenkins
459+
minCount: 1
460+
size: large
461+
type: jenkins
462+
463+
464+
API Server
465+
++++++++++
466+
467+
For API server you can overwrite the environment level by adding ``allowCIDRs``
468+
to the kubernetes block
469+
470+
.. code-block:: yaml
471+
472+
kubernetes:
473+
apiServer:
474+
public: true
475+
allowCIDRs:
476+
- y.y.y.y/24
416477
417478
Additional IAM policies
418479
~~~~~~~~~~~~~~~~~~~~~~~
@@ -459,4 +520,4 @@ It is possible to add extra policies to only a specific instance pool.
459520
zone: eu-west-1b
460521
- metadata:
461522
zone: eu-west-1c
462-
type: worker
523+
type: worker

pkg/apis/cluster/v1alpha1/cluster.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ type ClusterKubernetesDashboard struct {
103103

104104
type ClusterKubernetesAPIServer struct {
105105
// expose the API server through a public load balancer
106-
Public bool `json:"public,omitempty"`
106+
Public bool `json:"public,omitempty"`
107+
AllowCIDRs []string `json:"allowCIDRs,omitempty"`
107108

108109
// OIDC
109110
OIDC *ClusterKubernetesAPIServerOIDC `json:"oidc,omitempty"`

pkg/apis/cluster/v1alpha1/instancepool.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type InstancePool struct {
5555
Firewalls []*Firewall `json:"firewalls,omitempty"`
5656
Volumes []Volume `json:"volumes,omitempty"`
5757
Kubernetes *InstancePoolKubernetes `json:"kubernetes,omitempty"`
58+
AllowCIDRs []string `json:"allowCIDRs,omitempty"`
5859

5960
// Amazon specific settings for that instance pool
6061
Amazon *InstancePoolAmazon `json:"amazon,omitempty"`

pkg/apis/tarmak/v1alpha1/defaults.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ func SetDefaults_Environment(obj *Environment) {
2424
if obj.PrivateZone == "" {
2525
obj.PrivateZone = "tarmak.local"
2626
}
27+
28+
if obj.AdminCIDRs == nil {
29+
obj.AdminCIDRs = append(obj.AdminCIDRs, "0.0.0.0/0")
30+
}
2731
}
2832

2933
func SetDefaults_Config(obj *Config) {

pkg/apis/tarmak/v1alpha1/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ type Environment struct {
9090
Location string `json:"location,omitempty"`
9191
SSH *clusterv1alpha1.SSH `json:"ssh,omitempty"`
9292
PrivateZone string `json:"privateZone,omitempty"`
93+
AdminCIDRs []string `json:"adminCIDRs,omitempty"`
9394
}
9495

9596
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

pkg/tarmak/cluster/cluster.go

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,13 @@ func validateClusterTypes(poolMap map[string][]*clusterv1alpha1.InstancePool, cl
147147

148148
// validate server pools
149149
func (c *Cluster) validateInstancePools() (result error) {
150-
return nil
151-
//return fmt.Errorf("refactore me!")
150+
for _, instancePool := range c.InstancePools() {
151+
err := instancePool.Validate()
152+
if err != nil {
153+
result = multierror.Append(result, err)
154+
}
155+
}
156+
return result
152157
}
153158

154159
// Verify cluster
@@ -189,6 +194,15 @@ func (c *Cluster) Validate() (result error) {
189194
result = multierror.Append(result, err)
190195
}
191196

197+
//validate apiserver
198+
if k := c.Config().Kubernetes; k != nil {
199+
if apiServer := k.APIServer; apiServer != nil {
200+
if err := c.validateAPIServer(); err != nil {
201+
result = multierror.Append(result, err)
202+
}
203+
}
204+
}
205+
192206
return result
193207
}
194208

@@ -235,6 +249,18 @@ func (c *Cluster) validateLoggingSinks() (result error) {
235249
return nil
236250
}
237251

252+
// Validate APIServer
253+
func (c *Cluster) validateAPIServer() (result error) {
254+
for _, cidr := range c.Config().Kubernetes.APIServer.AllowCIDRs {
255+
_, _, err := net.ParseCIDR(cidr)
256+
if err != nil {
257+
result = multierror.Append(result, fmt.Errorf("%s is not a valid CIDR format", cidr))
258+
}
259+
}
260+
261+
return result
262+
}
263+
238264
// Determine if this Cluster is a cluster or hub, single or multi environment
239265
func (c *Cluster) Type() string {
240266
if c.conf.Type != "" {
@@ -392,6 +418,11 @@ func (c *Cluster) Variables() map[string]interface{} {
392418
if ok {
393419
output[fmt.Sprintf("%s_ami", instancePool.TFName())] = ids
394420
}
421+
if instancePool.Config().AllowCIDRs != nil {
422+
output[fmt.Sprintf("%s_admin_cidrs", instancePool.TFName())] = instancePool.Config().AllowCIDRs
423+
} else {
424+
output[fmt.Sprintf("%s_admin_cidrs", instancePool.TFName())] = c.environment.Config().AdminCIDRs
425+
}
395426
output[fmt.Sprintf("%s_min_instance_count", instancePool.TFName())] = instancePool.Config().MinCount
396427
output[fmt.Sprintf("%s_max_instance_count", instancePool.TFName())] = instancePool.Config().MaxCount
397428
}
@@ -426,6 +457,17 @@ func (c *Cluster) Variables() map[string]interface{} {
426457
}
427458
}
428459

460+
// Get Apiserver valid admin cidrs
461+
if k := c.Config().Kubernetes; k != nil {
462+
if apiServer := k.APIServer; apiServer != nil && apiServer.AllowCIDRs != nil {
463+
output["api_admin_cidrs"] = apiServer.AllowCIDRs
464+
} else {
465+
output["api_admin_cidrs"] = c.environment.Config().AdminCIDRs
466+
}
467+
} else {
468+
output["api_admin_cidrs"] = c.environment.Config().AdminCIDRs
469+
}
470+
429471
// publish changed private zone
430472
if privateZone := c.Environment().Config().PrivateZone; privateZone != "" {
431473
output["private_zone"] = privateZone

pkg/tarmak/environment/environment.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"golang.org/x/crypto/ssh"
1818
"k8s.io/client-go/rest"
1919

20+
"net"
21+
2022
clusterv1alpha1 "github.com/jetstack/tarmak/pkg/apis/cluster/v1alpha1"
2123
tarmakv1alpha1 "github.com/jetstack/tarmak/pkg/apis/tarmak/v1alpha1"
2224
"github.com/jetstack/tarmak/pkg/tarmak/cluster"
@@ -275,14 +277,27 @@ func (e *Environment) Log() *logrus.Entry {
275277
return e.log
276278
}
277279

278-
func (e *Environment) Validate() error {
279-
var result error
280+
func (e *Environment) Validate() (result error) {
280281

281-
err := e.Provider().Validate()
282-
if err != nil {
282+
if err := e.Provider().Validate(); err != nil {
283283
result = multierror.Append(result, err)
284284
}
285285

286+
if err := e.ValidateAdminCIDRs(); err != nil {
287+
result = multierror.Append(result, err)
288+
}
289+
290+
return result
291+
}
292+
293+
func (e *Environment) ValidateAdminCIDRs() (result error) {
294+
for _, cidr := range e.Config().AdminCIDRs {
295+
_, _, err := net.ParseCIDR(cidr)
296+
if err != nil {
297+
result = multierror.Append(result, fmt.Errorf("%s is not a valid CIDR format", cidr))
298+
}
299+
}
300+
286301
return result
287302
}
288303

pkg/tarmak/instance_pool/instance_pool.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/jetstack/tarmak/pkg/tarmak/interfaces"
1515
"github.com/jetstack/tarmak/pkg/tarmak/role"
1616
"github.com/jetstack/tarmak/pkg/tarmak/utils"
17+
"net"
1718
)
1819

1920
var _ interfaces.InstancePool = &InstancePool{}
@@ -185,3 +186,18 @@ func (n *InstancePool) AmazonAdditionalIAMPolicies() string {
185186

186187
return fmt.Sprintf("[%s]", strings.Join(policies, ","))
187188
}
189+
190+
func (n *InstancePool) Validate() (result error) {
191+
return n.ValidateAllowCIDRs()
192+
}
193+
194+
func (e *InstancePool) ValidateAllowCIDRs() (result error) {
195+
for _, cidr := range e.Config().AllowCIDRs {
196+
_, _, err := net.ParseCIDR(cidr)
197+
if err != nil {
198+
result = multierror.Append(result, fmt.Errorf("%s is not a valid CIDR format", cidr))
199+
}
200+
}
201+
202+
return result
203+
}

pkg/tarmak/interfaces/interfaces.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ type InstancePool interface {
248248
Role() *role.Role
249249
Volumes() []Volume
250250
Zones() []string
251+
Validate() error
251252
MinCount() int
252253
MaxCount() int
253254
}

0 commit comments

Comments
 (0)