Skip to content

Commit 63d78a6

Browse files
authored
Support disabling api gateway in cluster config (#1259)
1 parent cd8fa13 commit 63d78a6

File tree

15 files changed

+188
-37
lines changed

15 files changed

+188
-37
lines changed

cli/cmd/cluster.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -154,20 +154,26 @@ var _upCmd = &cobra.Command{
154154
exit.Error(err)
155155
}
156156

157-
err = createOrReplaceAPIGateway(awsClient, clusterConfig.ClusterName, clusterConfig.Tags)
158-
if err != nil {
159-
exit.Error(err)
157+
if clusterConfig.APIGatewaySetting == clusterconfig.EnabledAPIGatewaySetting {
158+
err = createOrReplaceAPIGateway(awsClient, clusterConfig.ClusterName, clusterConfig.Tags)
159+
if err != nil {
160+
exit.Error(err)
161+
}
160162
}
161163

162164
out, exitCode, err := runManagerUpdateCommand("/root/install.sh", clusterConfig, awsCreds, _flagClusterEnv)
163165
if err != nil {
164-
awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion
165-
awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion
166+
if clusterConfig.APIGatewaySetting == clusterconfig.EnabledAPIGatewaySetting {
167+
awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion
168+
awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion
169+
}
166170
exit.Error(err)
167171
}
168172
if exitCode == nil || *exitCode != 0 {
169-
awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion
170-
awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion
173+
if clusterConfig.APIGatewaySetting == clusterconfig.EnabledAPIGatewaySetting {
174+
awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion
175+
awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion
176+
}
171177
helpStr := "\nDebugging tips (may or may not apply to this error):"
172178
helpStr += fmt.Sprintf("\n* if your cluster started spinning up but was unable to provision instances, additional error information may be found in the activity history of your cluster's autoscaling groups (select each autoscaling group and click the \"Activity History\" tab): https://console.aws.amazon.com/ec2/autoscaling/home?region=%s#AutoScalingGroups:", *clusterConfig.Region)
173179
helpStr += fmt.Sprintf("\n* if your cluster started spinning up, please ensure that your CloudFormation stacks for this cluster have been fully deleted before trying to spin up this cluster again (you can delete your CloudFormation stacks from the AWS console: %s)", getCloudFormationURL(clusterConfig.ClusterName, *clusterConfig.Region))
@@ -322,7 +328,7 @@ var _downCmd = &cobra.Command{
322328
}
323329

324330
fmt.Print("○ deleting api gateway ")
325-
_, errAPIGateway := awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, *accessConfig.ClusterName)
331+
deletedAPIGateway, errAPIGateway := awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, *accessConfig.ClusterName)
326332
_, errVPCLink := awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, *accessConfig.ClusterName)
327333
if errAPIGateway != nil {
328334
fmt.Printf("\n\nunable to delete cortex's api gateway (see error below); if it still exists after the cluster has been deleted, please delete it via the api gateway console: https://%s.console.aws.amazon.com/apigateway/main/apis\n", *accessConfig.Region)
@@ -333,7 +339,11 @@ var _downCmd = &cobra.Command{
333339
errors.PrintError(errVPCLink)
334340
}
335341
if errAPIGateway == nil && errVPCLink == nil {
336-
fmt.Println("✓")
342+
if deletedAPIGateway != nil {
343+
fmt.Println("✓")
344+
} else {
345+
fmt.Println("(n/a)")
346+
}
337347
} else {
338348
fmt.Println()
339349
}

cli/cmd/lib_cluster_config.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,11 @@ func setConfigFieldsFromCached(userClusterConfig *clusterconfig.Config, cachedCl
315315
}
316316
userClusterConfig.OperatorLoadBalancerScheme = cachedClusterConfig.OperatorLoadBalancerScheme
317317

318+
if userClusterConfig.APIGatewaySetting != cachedClusterConfig.APIGatewaySetting {
319+
return clusterconfig.ErrorConfigCannotBeChangedOnUpdate(clusterconfig.APIGatewaySettingKey, cachedClusterConfig.APIGatewaySetting)
320+
}
321+
userClusterConfig.APIGatewaySetting = cachedClusterConfig.APIGatewaySetting
322+
318323
if userClusterConfig.Spot != nil && *userClusterConfig.Spot != *cachedClusterConfig.Spot {
319324
return clusterconfig.ErrorConfigCannotBeChangedOnUpdate(clusterconfig.SpotKey, *cachedClusterConfig.Spot)
320325
}
@@ -459,6 +464,10 @@ func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsCreds A
459464
}
460465
fmt.Printf("cortex will also create an s3 bucket (%s) and a cloudwatch log group (%s)%s\n\n", clusterConfig.Bucket, clusterConfig.LogGroup, privateSubnetMsg)
461466

467+
if clusterConfig.APIGatewaySetting == clusterconfig.DisabledAPIGatewaySetting {
468+
fmt.Print("warning: you've disabled API Gateway cluster-wide, so APIs will not be able to create API Gateway endpoints (they will still be reachable via the API load balancer; see https://docs.cortex.dev/deployments/networking for more information)\n\n")
469+
}
470+
462471
if clusterConfig.OperatorLoadBalancerScheme == clusterconfig.InternalLoadBalancerScheme {
463472
fmt.Print("warning: you've configured the operator load balancer to be internal; you must configure VPC Peering to connect your CLI to your cluster operator (see https://docs.cortex.dev/guides/vpc-peering)\n\n")
464473
}
@@ -535,6 +544,9 @@ func clusterConfigConfirmationStr(clusterConfig clusterconfig.Config, awsCreds A
535544
if clusterConfig.OperatorLoadBalancerScheme != defaultConfig.OperatorLoadBalancerScheme {
536545
items.Add(clusterconfig.OperatorLoadBalancerSchemeUserKey, clusterConfig.OperatorLoadBalancerScheme)
537546
}
547+
if clusterConfig.APIGatewaySetting != defaultConfig.APIGatewaySetting {
548+
items.Add(clusterconfig.APIGatewaySettingUserKey, clusterConfig.APIGatewaySetting)
549+
}
538550

539551
if clusterConfig.Spot != nil && *clusterConfig.Spot != *defaultConfig.Spot {
540552
items.Add(clusterconfig.SpotUserKey, s.YesNo(clusterConfig.Spot != nil && *clusterConfig.Spot))

docs/cluster-management/config.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ api_load_balancer_scheme: internet-facing # must be "internet-facing" or "inter
6666
# see https://docs.cortex.dev/v/master/miscellaneous/security#private-cluster for more information
6767
operator_load_balancer_scheme: internet-facing # must be "internet-facing" or "internal"
6868

69+
# whether to disable API gateway cluster-wide
70+
# if set to "enabled" (the default), each API can specify whether to use API Gateway
71+
# if set to "disabled", no APIs will be allowed to use API Gateway
72+
api_gateway: enabled # must be "enabled" or "disabled"
73+
6974
# CloudWatch log group for cortex (default: <cluster_name>)
7075
log_group: cortex
7176

docs/deployments/networking.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ _WARNING: you are on the master branch, please refer to the docs on the branch t
44

55
![api architecture diagram](https://user-images.githubusercontent.com/808475/84695323-8507dd00-aeff-11ea-8b32-5a55cef76c79.png)
66

7-
APIs are deployed with a public API Gateway by default (the API Gateway forwards requests to the API load balancer). Each API can be independently configured to not create the API Gateway endpoint by setting `api_gateway: none` in the `networking` field of the [api configuration](api-configuration.md). If the API Gateway endpoint is not created, your API can still be accessed via the API load balancer; `cortex get API_NAME` will show the load balancer endpoint if API Gateway is disabled. API Gateway is enabled by default, and is generally recommended unless it doesn't support your use case due to limitations such as the 29 second request timeout, or if you are keeping your APIs private to your VPC. See below for common configurations.
7+
APIs are deployed with a public API Gateway by default (the API Gateway forwards requests to the API load balancer). Each API can be independently configured to not create the API Gateway endpoint by setting `api_gateway: none` in the `networking` field of the [api configuration](api-configuration.md). If the API Gateway endpoint is not created, your API can still be accessed via the API load balancer; `cortex get API_NAME` will show the load balancer endpoint if API Gateway is disabled. API Gateway is enabled by default, and is generally recommended unless it doesn't support your use case due to limitations such as the 29 second request timeout, or if you are keeping your APIs private to your VPC. See below for common configurations. To disable API Gateway cluster-wide (thereby enforcing that all APIs cannot create API Gateway endpoints), set `api_gateway: disabled` in your [cluster configuration](../cluster-management/config.md) file (before creating your cluster).
88

99
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](../cluster-management/config.md) file (before creating your cluster). This will force external traffic to go through your API Gateway endpoint, or if you disabled API Gateway for your API, it will make your API only accessible through VPC Peering. Note that if API Gateway is used, endpoints will be public regardless of `api_load_balancer_scheme`. See below for common configurations.
1010

manager/install.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ function main() {
167167
ensure_eks
168168

169169
# create VPC Link for API Gateway
170-
if [ "$arg1" != "--update" ] && [ "$CORTEX_API_LOAD_BALANCER_SCHEME" == "internal" ]; then
170+
if [ "$arg1" != "--update" ] && [ "$CORTEX_API_LOAD_BALANCER_SCHEME" == "internal" ] && [ "$CORTEX_API_GATEWAY" == "enabled" ]; then
171171
vpc_id=$(aws ec2 describe-vpcs --region $CORTEX_REGION --filters Name=tag:eksctl.cluster.k8s.io/v1alpha1/cluster-name,Values=$CORTEX_CLUSTER_NAME | jq .Vpcs[0].VpcId | tr -d '"')
172172
if [ "$vpc_id" = "" ] || [ "$vpc_id" = "null" ]; then
173173
echo "unable to find cortex vpc"
@@ -247,7 +247,7 @@ function main() {
247247
fi
248248

249249
# add VPC Link integration to API Gateway
250-
if [ "$arg1" != "--update" ] && [ "$CORTEX_API_LOAD_BALANCER_SCHEME" == "internal" ]; then
250+
if [ "$arg1" != "--update" ] && [ "$CORTEX_API_LOAD_BALANCER_SCHEME" == "internal" ] && [ "$CORTEX_API_GATEWAY" == "enabled" ]; then
251251
echo -n "○ creating api gateway vpc link integration "
252252
api_id=$(python get_api_gateway_id.py)
253253
python create_gateway_integration.py $api_id $vpc_link_id

pkg/lib/aws/apigateway.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func (c *Client) GetAPIGatewayByTag(tagName string, tagValue string) (*apigatewa
111111
return nil, nil
112112
}
113113

114-
// DeleteVPCLinkByTag Deletes a VPC Link by tag (returns the deleted VPC Link, or nil if it was not found )
114+
// DeleteVPCLinkByTag Deletes a VPC Link by tag (returns the deleted VPC Link, or nil if it was not found)
115115
func (c *Client) DeleteVPCLinkByTag(tagName string, tagValue string) (*apigatewayv2.VpcLink, error) {
116116
vpcLink, err := c.GetVPCLinkByTag(tagName, tagValue)
117117
if err != nil {
@@ -130,7 +130,7 @@ func (c *Client) DeleteVPCLinkByTag(tagName string, tagValue string) (*apigatewa
130130
return vpcLink, nil
131131
}
132132

133-
// DeleteAPIGatewayByTag Deletes an API Gateway by tag (returns whether or not the API Gateway existed)
133+
// DeleteAPIGatewayByTag Deletes an API Gateway by tag (returns the deleted API Gateway, or nil if it was not found)
134134
func (c *Client) DeleteAPIGatewayByTag(tagName string, tagValue string) (*apigatewayv2.Api, error) {
135135
apiGateway, err := c.GetAPIGatewayByTag(tagName, tagValue)
136136
if err != nil {

pkg/operator/config/config.go

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -86,30 +86,32 @@ func Init() error {
8686
fmt.Println(errors.Message(err))
8787
}
8888

89-
apiGateway, err := AWS.GetAPIGatewayByTag(clusterconfig.ClusterNameTag, Cluster.ClusterName)
90-
if err != nil {
91-
return err
92-
} else if apiGateway == nil {
93-
return ErrorNoAPIGateway()
94-
}
95-
Cluster.APIGateway = *apiGateway
96-
97-
if Cluster.APILoadBalancerScheme == clusterconfig.InternalLoadBalancerScheme {
98-
vpcLink, err := AWS.GetVPCLinkByTag(clusterconfig.ClusterNameTag, Cluster.ClusterName)
89+
if Cluster.APIGatewaySetting == clusterconfig.EnabledAPIGatewaySetting {
90+
apiGateway, err := AWS.GetAPIGatewayByTag(clusterconfig.ClusterNameTag, Cluster.ClusterName)
9991
if err != nil {
10092
return err
101-
} else if vpcLink == nil {
102-
return ErrorNoVPCLink()
93+
} else if apiGateway == nil {
94+
return ErrorNoAPIGateway()
10395
}
104-
Cluster.VPCLink = vpcLink
105-
106-
integration, err := AWS.GetVPCLinkIntegration(*Cluster.APIGateway.ApiId, *Cluster.VPCLink.VpcLinkId)
107-
if err != nil {
108-
return err
109-
} else if integration == nil {
110-
return ErrorNoVPCLinkIntegration()
96+
Cluster.APIGateway = apiGateway
97+
98+
if Cluster.APILoadBalancerScheme == clusterconfig.InternalLoadBalancerScheme {
99+
vpcLink, err := AWS.GetVPCLinkByTag(clusterconfig.ClusterNameTag, Cluster.ClusterName)
100+
if err != nil {
101+
return err
102+
} else if vpcLink == nil {
103+
return ErrorNoVPCLink()
104+
}
105+
Cluster.VPCLink = vpcLink
106+
107+
integration, err := AWS.GetVPCLinkIntegration(*Cluster.APIGateway.ApiId, *Cluster.VPCLink.VpcLinkId)
108+
if err != nil {
109+
return err
110+
} else if integration == nil {
111+
return ErrorNoVPCLinkIntegration()
112+
}
113+
Cluster.VPCLinkIntegration = integration
111114
}
112-
Cluster.VPCLinkIntegration = integration
113115
}
114116

115117
Cluster.InstanceMetadata = aws.InstanceMetadatas[*Cluster.Region][*Cluster.InstanceType]

pkg/operator/operator/gateway.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ import (
2727
)
2828

2929
func AddAPIToAPIGateway(endpoint string, apiGatewayType userconfig.APIGatewayType) error {
30+
if config.Cluster.APIGateway == nil {
31+
return nil
32+
}
33+
3034
if apiGatewayType == userconfig.NoneAPIGatewayType {
3135
return nil
3236
}
@@ -71,6 +75,10 @@ func AddAPIToAPIGateway(endpoint string, apiGatewayType userconfig.APIGatewayTyp
7175
}
7276

7377
func RemoveAPIFromAPIGateway(endpoint string, apiGatewayType userconfig.APIGatewayType) error {
78+
if config.Cluster.APIGateway == nil {
79+
return nil
80+
}
81+
7482
if apiGatewayType == userconfig.NoneAPIGatewayType {
7583
return nil
7684
}
@@ -102,6 +110,10 @@ func UpdateAPIGateway(
102110
newAPIGatewayType userconfig.APIGatewayType,
103111
) error {
104112

113+
if config.Cluster.APIGateway == nil {
114+
return nil
115+
}
116+
105117
if prevAPIGatewayType == userconfig.NoneAPIGatewayType && newAPIGatewayType == userconfig.NoneAPIGatewayType {
106118
return nil
107119
}

pkg/operator/resources/apisplitter/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func areVirtualServiceEqual(vs1, vs2 *istioclientnetworking.VirtualService) bool
160160

161161
// APIBaseURL returns BaseURL of the API without resource endpoint
162162
func APIBaseURL(api *spec.API) (string, error) {
163-
if api.Networking.APIGateway == userconfig.PublicAPIGatewayType {
163+
if api.Networking.APIGateway == userconfig.PublicAPIGatewayType && config.Cluster.APIGateway != nil {
164164
return *config.Cluster.APIGateway.ApiEndpoint, nil
165165
}
166166
return operator.APILoadBalancerURL()

pkg/operator/resources/errors.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/cortexlabs/cortex/pkg/lib/errors"
2323
"github.com/cortexlabs/cortex/pkg/lib/strings"
24+
s "github.com/cortexlabs/cortex/pkg/lib/strings"
2425
"github.com/cortexlabs/cortex/pkg/types/userconfig"
2526
)
2627

@@ -31,6 +32,7 @@ const (
3132
ErrNoAvailableNodeComputeLimit = "resources.no_available_node_compute_limit"
3233
ErrAPIUsedByAPISplitter = "resources.syncapi_used_by_apisplitter"
3334
ErrNotDeployedAPIsAPISplitter = "resources.trafficsplit_apis_not_deployed"
35+
ErrAPIGatewayDisabled = "resources.api_gateway_disabled"
3436
)
3537

3638
func ErrorOperationNotSupportedForKind(kind userconfig.Kind) error {
@@ -78,3 +80,15 @@ func ErrorNotDeployedAPIsAPISplitter(notDeployedAPIs []string) error {
7880
Message: fmt.Sprintf("unable to find specified %s: %s", strings.PluralS("api", len(notDeployedAPIs)), strings.StrsAnd(notDeployedAPIs)),
7981
})
8082
}
83+
84+
func ErrorAPIGatewayDisabled(apiGatewayType userconfig.APIGatewayType) error {
85+
msg := fmt.Sprintf("%s is not permitted because api gateway is disabled cluster-wide", s.UserStr(apiGatewayType))
86+
if apiGatewayType == userconfig.PublicAPIGatewayType {
87+
msg += fmt.Sprintf(" (%s is the default value, and the valid values are %s)", s.UserStr(userconfig.PublicAPIGatewayType), s.UserStrsAnd(userconfig.APIGatewayTypeStrings()))
88+
}
89+
90+
return errors.WithStack(&errors.Error{
91+
Kind: ErrAPIGatewayDisabled,
92+
Message: msg,
93+
})
94+
}

0 commit comments

Comments
 (0)