From bd5c59587200c6121d0fbce6f4ff96cf01971274 Mon Sep 17 00:00:00 2001 From: vishal Date: Fri, 9 Apr 2021 14:57:03 -0400 Subject: [PATCH 1/4] Whitelist IP addresses --- cli/cmd/lib_realtime_apis.go | 8 ++- docs/clusters/management/create.md | 6 +++ docs/clusters/networking/load-balancers.md | 4 +- manager/manifests/istio.yaml.j2 | 7 +++ pkg/types/clusterconfig/cluster_config.go | 58 ++++++++++++++++------ 5 files changed, 66 insertions(+), 17 deletions(-) diff --git a/cli/cmd/lib_realtime_apis.go b/cli/cmd/lib_realtime_apis.go index 9ff3f1a883..de64024619 100644 --- a/cli/cmd/lib_realtime_apis.go +++ b/cli/cmd/lib_realtime_apis.go @@ -167,6 +167,9 @@ func describeModelInput(status *status.Status, predictor *userconfig.Predictor, if predictor.Type == userconfig.TensorFlowPredictorType && !cachingEnabled { apiTFLiveReloadingSummary, err := getAPITFLiveReloadingSummary(apiEndpoint) if err != nil { + if strings.Contains(errors.Message(err), "context deadline exceeded") { + return "error retrieving the models' metadata schema: unable to connect to the API, you either do not have access or the API is too busy" + "\n" + } return "error retrieving the models' metadata schema: " + errors.Message(err) + "\n" } t, err := parseAPITFLiveReloadingSummary(apiTFLiveReloadingSummary) @@ -178,6 +181,9 @@ func describeModelInput(status *status.Status, predictor *userconfig.Predictor, apiModelSummary, err := getAPIModelSummary(apiEndpoint) if err != nil { + if strings.Contains(errors.Message(err), "context deadline exceeded") { + return "error retrieving the models' metadata schema: unable to connect to the API, you either do not have access or the API is too busy" + "\n" + } return "error retrieving the models' metadata schema: " + errors.Message(err) + "\n" } t, err := parseAPIModelSummary(apiModelSummary) @@ -196,7 +202,7 @@ func getModelFromModelID(modelID string) (modelName string, modelVersion int64, func makeRequest(request *http.Request) (http.Header, []byte, error) { client := http.Client{ - Timeout: 600 * time.Second, + Timeout: 5 * time.Second, Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }, diff --git a/docs/clusters/management/create.md b/docs/clusters/management/create.md index c8ba400b35..b7c8e613a2 100644 --- a/docs/clusters/management/create.md +++ b/docs/clusters/management/create.md @@ -82,6 +82,12 @@ operator_load_balancer_scheme: internet-facing # - availability_zone: us-west-2b # subnet_id: subnet-0faed05adf6042ab7 +# restrict access to APIs by cidr blocks/ip address ranges +api_load_balancer_cidr_white_list: [0.0.0.0/0] + +# restrict access to the Operator by cidr blocks/ip address ranges +operator_load_balancer_cidr_white_list: [0.0.0.0/0] + # additional tags to assign to AWS resources (all resources will automatically be tagged with cortex.dev/cluster-name: ) tags: # : map of key/value pairs diff --git a/docs/clusters/networking/load-balancers.md b/docs/clusters/networking/load-balancers.md index c67da5e2fd..5fbe3c9c66 100644 --- a/docs/clusters/networking/load-balancers.md +++ b/docs/clusters/networking/load-balancers.md @@ -2,8 +2,8 @@ ![api architecture diagram](https://user-images.githubusercontent.com/808475/103417256-dd6e9700-4b3e-11eb-901e-90425f1f8fd4.png) -All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). This will make your API only accessible through [VPC Peering](vpc-peering.md). +All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). This will make your API only accessible through [VPC Peering](vpc-peering.md). You can restrict access to APIs by ip address ranges by specifying `api_load_balancer_cidr_white_list: []` in your cluster configuration. The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to skip certificate verification when making HTTPS requests to your APIs (e.g. `curl -k https://***`), or make HTTP requests instead (e.g. `curl http://***`). Alternatively, you can enable HTTPS by using a [custom domain](custom-domain.md) or by [creating an API Gateway](https.md) to forward requests to your API load balancer. -There is a separate load balancer for the Cortex operator. By default, the operator load balancer is public. You can configure your operator load balancer to be private by setting `operator_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). You can use [VPC Peering](vpc-peering.md) to enable your Cortex CLI to connect to your cluster operator from another VPC. +There is a separate load balancer for the Cortex operator. By default, the operator load balancer is public. You can configure your operator load balancer to be private by setting `operator_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). You can use [VPC Peering](vpc-peering.md) to enable your Cortex CLI to connect to your cluster operator from another VPC. You can restrict access to the Cortex operator by ip address ranges by specifying `operator_load_balancer_cidr_white_list: []` in your cluster configuration. diff --git a/manager/manifests/istio.yaml.j2 b/manager/manifests/istio.yaml.j2 index e17e411266..f09a5fcbfa 100644 --- a/manager/manifests/istio.yaml.j2 +++ b/manager/manifests/istio.yaml.j2 @@ -50,6 +50,9 @@ spec: service: type: LoadBalancer externalTrafficPolicy: Cluster # https://medium.com/pablo-perez/k8s-externaltrafficpolicy-local-or-cluster-40b259a19404, https://www.asykim.com/blog/deep-dive-into-kubernetes-external-traffic-policies + {% if config.get('operator_load_balancer_cidr_white_list', [])|length > 0 %} + loadBalancerSourceRanges: {{ config['operator_load_balancer_cidr_white_list'] }} + {% endif %} selector: app: operator-istio-gateway istio: ingressgateway-operator @@ -107,6 +110,10 @@ spec: {% endif %} service: type: LoadBalancer + {% if config.get('api_load_balancer_cidr_white_list', [])|length > 0 %} + loadBalancerSourceRanges: {{ config['api_load_balancer_cidr_white_list'] }} + {% endif %} + selector: externalTrafficPolicy: Cluster # https://medium.com/pablo-perez/k8s-externaltrafficpolicy-local-or-cluster-40b259a19404, https://www.asykim.com/blog/deep-dive-into-kubernetes-external-traffic-policies selector: app: apis-istio-gateway diff --git a/pkg/types/clusterconfig/cluster_config.go b/pkg/types/clusterconfig/cluster_config.go index a16fbce6d5..b86e5fe474 100644 --- a/pkg/types/clusterconfig/cluster_config.go +++ b/pkg/types/clusterconfig/cluster_config.go @@ -98,18 +98,20 @@ type CoreConfig struct { } type ManagedConfig struct { - NodeGroups []*NodeGroup `json:"node_groups" yaml:"node_groups"` - Tags map[string]string `json:"tags" yaml:"tags"` - AvailabilityZones []string `json:"availability_zones" yaml:"availability_zones"` - SSLCertificateARN *string `json:"ssl_certificate_arn,omitempty" yaml:"ssl_certificate_arn,omitempty"` - IAMPolicyARNs []string `json:"iam_policy_arns" yaml:"iam_policy_arns"` - SubnetVisibility SubnetVisibility `json:"subnet_visibility" yaml:"subnet_visibility"` - Subnets []*Subnet `json:"subnets,omitempty" yaml:"subnets,omitempty"` - NATGateway NATGateway `json:"nat_gateway" yaml:"nat_gateway"` - APILoadBalancerScheme LoadBalancerScheme `json:"api_load_balancer_scheme" yaml:"api_load_balancer_scheme"` - OperatorLoadBalancerScheme LoadBalancerScheme `json:"operator_load_balancer_scheme" yaml:"operator_load_balancer_scheme"` - VPCCIDR *string `json:"vpc_cidr,omitempty" yaml:"vpc_cidr,omitempty"` - CortexPolicyARN string `json:"cortex_policy_arn" yaml:"cortex_policy_arn"` // this field is not user facing + NodeGroups []*NodeGroup `json:"node_groups" yaml:"node_groups"` + Tags map[string]string `json:"tags" yaml:"tags"` + AvailabilityZones []string `json:"availability_zones" yaml:"availability_zones"` + SSLCertificateARN *string `json:"ssl_certificate_arn,omitempty" yaml:"ssl_certificate_arn,omitempty"` + IAMPolicyARNs []string `json:"iam_policy_arns" yaml:"iam_policy_arns"` + SubnetVisibility SubnetVisibility `json:"subnet_visibility" yaml:"subnet_visibility"` + Subnets []*Subnet `json:"subnets,omitempty" yaml:"subnets,omitempty"` + NATGateway NATGateway `json:"nat_gateway" yaml:"nat_gateway"` + APILoadBalancerScheme LoadBalancerScheme `json:"api_load_balancer_scheme" yaml:"api_load_balancer_scheme"` + OperatorLoadBalancerScheme LoadBalancerScheme `json:"operator_load_balancer_scheme" yaml:"operator_load_balancer_scheme"` + APILoadBalancerCIDRWhiteList []string `json:"api_load_balancer_cidr_white_list,omitempty" yaml:"api_load_balancer_cidr_white_list,omitempty"` + OperatorLoadBalancerCIDRWhiteList []string `json:"operator_load_balancer_cidr_white_list,omitempty" yaml:"operator_load_balancer_cidr_white_list,omitempty"` + VPCCIDR *string `json:"vpc_cidr,omitempty" yaml:"vpc_cidr,omitempty"` + CortexPolicyARN string `json:"cortex_policy_arn" yaml:"cortex_policy_arn"` // this field is not user facing } type NodeGroup struct { @@ -663,6 +665,34 @@ var ManagedConfigStructFieldValidations = []*cr.StructFieldValidation{ return LoadBalancerSchemeFromString(str), nil }, }, + { + StructField: "APILoadBalancerCIDRWhiteList", + StringListValidation: &cr.StringListValidation{ + Validator: func(addresses []string) ([]string, error) { + for i, address := range addresses { + _, err := validateCIDR(address) + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("index %d", i)) + } + } + return addresses, nil + }, + }, + }, + { + StructField: "OperatorLoadBalancerCIDRWhiteList", + StringListValidation: &cr.StringListValidation{ + Validator: func(addresses []string) ([]string, error) { + for i, address := range addresses { + _, err := validateCIDR(address) + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("index %d", i)) + } + } + return addresses, nil + }, + }, + }, { StructField: "OperatorLoadBalancerScheme", StringValidation: &cr.StringValidation{ @@ -676,7 +706,7 @@ var ManagedConfigStructFieldValidations = []*cr.StructFieldValidation{ { StructField: "VPCCIDR", StringPtrValidation: &cr.StringPtrValidation{ - Validator: validateVPCCIDR, + Validator: validateCIDR, }, }, } @@ -1083,7 +1113,7 @@ func validateBucketName(bucket string) (string, error) { return bucket, nil } -func validateVPCCIDR(cidr string) (string, error) { +func validateCIDR(cidr string) (string, error) { _, _, err := net.ParseCIDR(cidr) if err != nil { return "", errors.WithStack(err) From 06d687de21a05581ca45c23a9bb86f1b786ee564 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Fri, 9 Apr 2021 14:01:58 -0700 Subject: [PATCH 2/4] Update load-balancers.md --- docs/clusters/networking/load-balancers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/clusters/networking/load-balancers.md b/docs/clusters/networking/load-balancers.md index 5fbe3c9c66..0520e9be27 100644 --- a/docs/clusters/networking/load-balancers.md +++ b/docs/clusters/networking/load-balancers.md @@ -2,8 +2,8 @@ ![api architecture diagram](https://user-images.githubusercontent.com/808475/103417256-dd6e9700-4b3e-11eb-901e-90425f1f8fd4.png) -All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). This will make your API only accessible through [VPC Peering](vpc-peering.md). You can restrict access to APIs by ip address ranges by specifying `api_load_balancer_cidr_white_list: []` in your cluster configuration. +All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). This will make your API only accessible through [VPC Peering](vpc-peering.md). You can restrict API access to specific ip address ranges by specifying `api_load_balancer_cidr_white_list: []` in your cluster configuration. The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to skip certificate verification when making HTTPS requests to your APIs (e.g. `curl -k https://***`), or make HTTP requests instead (e.g. `curl http://***`). Alternatively, you can enable HTTPS by using a [custom domain](custom-domain.md) or by [creating an API Gateway](https.md) to forward requests to your API load balancer. -There is a separate load balancer for the Cortex operator. By default, the operator load balancer is public. You can configure your operator load balancer to be private by setting `operator_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). You can use [VPC Peering](vpc-peering.md) to enable your Cortex CLI to connect to your cluster operator from another VPC. You can restrict access to the Cortex operator by ip address ranges by specifying `operator_load_balancer_cidr_white_list: []` in your cluster configuration. +There is a separate load balancer for the Cortex operator. By default, the operator load balancer is public. You can configure your operator load balancer to be private by setting `operator_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). You can use [VPC Peering](vpc-peering.md) to enable your Cortex CLI to connect to your cluster operator from another VPC. You can restrict Cortex operator access to specific ip address ranges by specifying `operator_load_balancer_cidr_white_list: []` in your cluster configuration. From 8e94424fff63cca4f00f5104885f0ade039643b6 Mon Sep 17 00:00:00 2001 From: vishal Date: Fri, 9 Apr 2021 17:45:41 -0400 Subject: [PATCH 3/4] Remove unnecessary field --- manager/manifests/istio.yaml.j2 | 1 - 1 file changed, 1 deletion(-) diff --git a/manager/manifests/istio.yaml.j2 b/manager/manifests/istio.yaml.j2 index f09a5fcbfa..5aa8c61eb2 100644 --- a/manager/manifests/istio.yaml.j2 +++ b/manager/manifests/istio.yaml.j2 @@ -113,7 +113,6 @@ spec: {% if config.get('api_load_balancer_cidr_white_list', [])|length > 0 %} loadBalancerSourceRanges: {{ config['api_load_balancer_cidr_white_list'] }} {% endif %} - selector: externalTrafficPolicy: Cluster # https://medium.com/pablo-perez/k8s-externaltrafficpolicy-local-or-cluster-40b259a19404, https://www.asykim.com/blog/deep-dive-into-kubernetes-external-traffic-policies selector: app: apis-istio-gateway From d17f64bc868f613c5c61c9ff29ab7f1369c7b8f3 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Fri, 9 Apr 2021 15:01:32 -0700 Subject: [PATCH 4/4] Update load-balancers.md --- docs/clusters/networking/load-balancers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/clusters/networking/load-balancers.md b/docs/clusters/networking/load-balancers.md index 0520e9be27..ad76bc7445 100644 --- a/docs/clusters/networking/load-balancers.md +++ b/docs/clusters/networking/load-balancers.md @@ -2,8 +2,8 @@ ![api architecture diagram](https://user-images.githubusercontent.com/808475/103417256-dd6e9700-4b3e-11eb-901e-90425f1f8fd4.png) -All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). This will make your API only accessible through [VPC Peering](vpc-peering.md). You can restrict API access to specific ip address ranges by specifying `api_load_balancer_cidr_white_list: []` in your cluster configuration. +All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). This will make your API only accessible through [VPC Peering](vpc-peering.md). You can enforce that incoming requests to APIs must originate from specific ip address ranges by specifying `api_load_balancer_cidr_white_list: []` in your cluster configuration. The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to skip certificate verification when making HTTPS requests to your APIs (e.g. `curl -k https://***`), or make HTTP requests instead (e.g. `curl http://***`). Alternatively, you can enable HTTPS by using a [custom domain](custom-domain.md) or by [creating an API Gateway](https.md) to forward requests to your API load balancer. -There is a separate load balancer for the Cortex operator. By default, the operator load balancer is public. You can configure your operator load balancer to be private by setting `operator_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). You can use [VPC Peering](vpc-peering.md) to enable your Cortex CLI to connect to your cluster operator from another VPC. You can restrict Cortex operator access to specific ip address ranges by specifying `operator_load_balancer_cidr_white_list: []` in your cluster configuration. +There is a separate load balancer for the Cortex operator. By default, the operator load balancer is public. You can configure your operator load balancer to be private by setting `operator_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). You can use [VPC Peering](vpc-peering.md) to enable your Cortex CLI to connect to your cluster operator from another VPC. You can enforce that incoming requests to the Cortex operator must originate from specific ip address ranges by specifying `operator_load_balancer_cidr_white_list: []` in your cluster configuration.