Skip to content

Commit

Permalink
Merge pull request #111 from gympass/PE1-2013/deprecation-manager
Browse files Browse the repository at this point in the history
[PE1-2013] feat: allow blocking creation of distributions, filtered by allow list
  • Loading branch information
LCaparelli authored Dec 11, 2023
2 parents 81a4b82 + 34e37cd commit 1a96332
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 25 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ CF_DEFAULT_CACHING_POLICY_ID="4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
CF_DEFAULT_CACHE_REQUEST_POLICY_ID="216adef6-5c7f-47e4-b989-5492eafa07d3"
CF_DEFAULT_PUBLIC_ORIGIN_ACCESS_REQUEST_POLICY_ID="216adef6-5c7f-47e4-b989-5492eafa07d3"
CF_DEFAULT_BUCKET_ORIGIN_ACCESS_REQUEST_POLICY_ID="88a5eaf4-2fd4-4709-b370-b4c650ea3fcf"
BLOCK_CREATION="false"
# BLOCK_CREATION_ALLOW_LIST="namespace/name,another-namespace/name"
30 changes: 16 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,20 +295,22 @@ Access the [documentation](https://gympass.github.io/cdn-origin-controller/) to

Use the following environment variables to change the controller's behavior:

| Env var key | Required | Description | Default |
|--------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------|
| CF_AWS_WAF | No | The Web ACL which should be associated with the distributions. Use the ID for WAF v1 and the ARN for WAF v2. | "" |
| CF_CUSTOM_TAGS | No | Comma-separated list of custom tags to be added to distributions. Example: "foo=bar,bar=foo" | "" |
| CF_DEFAULT_ORIGIN_DOMAIN | Yes | Domain of the default origin each distribution must have to route traffic to in case no custom behaviors match the request. | "" |
| CF_DESCRIPTION_TEMPLATE | No | Template of the distribution's description. Currently a single field can be accessed, `{{group}}`, which matches the CDN group under which the distribution was provisioned. | "Serve contents for {{group}} group." |
| CF_ENABLE_IPV6 | No | Whether the distribution should also expose an IPv6 address to serve requests. | "true" |
| CF_ENABLE_LOGGING | No | If set to true enables sending logs to CloudWatch; `CF_S3_BUCKET_LOG` must be set as well. | "false" |
| CF_PRICE_CLASS | Yes | The distribution price class. Possible values are: "PriceClass_All", "PriceClass_200", "PriceClass_100". [Official reference](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PriceClass.html). | "PriceClass_All" |
| CF_S3_BUCKET_LOG | No | The domain of the S3 bucket CloudWatch logs should be sent to. Each distribution will have its own directory inside the bucket with the same as the distribution's group. For example, if the group is "foo", the logs will be stored as `foo/<ID>.<timestamp and hash>.gz`.<br><br> If `CF_ENABLE_LOGGING` is not set to "true" then this value is ignored. | "" |
| CF_SECURITY_POLICY | No | The TLS/SSL security policy to be used when serving requests. [Official reference](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/secure-connections-supported-viewer-protocols-ciphers.html). <br><br> Must also inform a valid `CF_CUSTOM_SSL_CERT` if set. | "" |
| DEV_MODE | No | When set to "true" logs in unstructured text instead of JSON. Also overrides LOG_LEVEL to "debug". | "false" |
| LOG_LEVEL | No | Represents log level of verbosity. Can be "debug", "info", "warn", "error", "dpanic", "panic" and "fatal" (sorted with decreasing verbosity). | "info" |
| ENABLE_DELETION | No | Represent whether CloudFront Distributions and Route53 records should be deleted based on Ingresses being deleted. Ownership TXT DNS records are also not deleted to allow for self-healing in case of accidental deletion of Kubernetes resources. | "false" |
| Env var key | Required | Description | Default |
|---------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------|
| CF_AWS_WAF | No | The Web ACL which should be associated with the distributions. Use the ID for WAF v1 and the ARN for WAF v2. | "" |
| CF_CUSTOM_TAGS | No | Comma-separated list of custom tags to be added to distributions. Example: "foo=bar,bar=foo" | "" |
| CF_DEFAULT_ORIGIN_DOMAIN | Yes | Domain of the default origin each distribution must have to route traffic to in case no custom behaviors match the request. | "" |
| CF_DESCRIPTION_TEMPLATE | No | Template of the distribution's description. Currently a single field can be accessed, `{{group}}`, which matches the CDN group under which the distribution was provisioned. | "Serve contents for {{group}} group." |
| CF_ENABLE_IPV6 | No | Whether the distribution should also expose an IPv6 address to serve requests. | "true" |
| CF_ENABLE_LOGGING | No | If set to true enables sending logs to CloudWatch; `CF_S3_BUCKET_LOG` must be set as well. | "false" |
| CF_PRICE_CLASS | Yes | The distribution price class. Possible values are: "PriceClass_All", "PriceClass_200", "PriceClass_100". [Official reference](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PriceClass.html). | "PriceClass_All" |
| CF_S3_BUCKET_LOG | No | The domain of the S3 bucket CloudWatch logs should be sent to. Each distribution will have its own directory inside the bucket with the same as the distribution's group. For example, if the group is "foo", the logs will be stored as `foo/<ID>.<timestamp and hash>.gz`.<br><br> If `CF_ENABLE_LOGGING` is not set to "true" then this value is ignored. | "" |
| CF_SECURITY_POLICY | No | The TLS/SSL security policy to be used when serving requests. [Official reference](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/secure-connections-supported-viewer-protocols-ciphers.html). <br><br> Must also inform a valid `CF_CUSTOM_SSL_CERT` if set. | "" |
| DEV_MODE | No | When set to "true" logs in unstructured text instead of JSON. Also overrides LOG_LEVEL to "debug". | "false" |
| LOG_LEVEL | No | Represents log level of verbosity. Can be "debug", "info", "warn", "error", "dpanic", "panic" and "fatal" (sorted with decreasing verbosity). | "info" |
| ENABLE_DELETION | No | Represent whether CloudFront Distributions and Route53 records should be deleted based on Ingresses being deleted. Ownership TXT DNS records are also not deleted to allow for self-healing in case of accidental deletion of Kubernetes resources. | "false" |
| BLOCK_CREATION | No | Boolean value to configure the controller to block creation of new CloudFront Distributions. Useful when phasing out clusters or accounts, for example. | "false" |
| BLOCK_CREATION_ALLOW_LIST | No | Comma-separated list of namespaced names of Ingresses that should override BLOCK_CREATION, and be allowed to always move forward with creating a new Distribution. Ex: "namespace/name,another-namespace/another-name". | "" |

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion internal/cloudfront/distribution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func (s *DistributionTestSuite) TestDistributionBuilder_WithOrigin() {
ResponseTimeout: 30,
}

dist, err := cloudfront.NewDistributionBuilder(group, config.Parse()).
dist, err := cloudfront.NewDistributionBuilder(group, s.cfg).
WithOrigin(origin).
Build()

Expand Down
22 changes: 19 additions & 3 deletions internal/cloudfront/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (s *Service) Reconcile(ctx context.Context, ing *networkingv1.Ingress, clas

reconciling, err := k8s.NewCDNIngressFromV1(ctx, ing, class)
if err != nil {
return err
return s.handleFailure(err, ing)
}

log, _ := logr.FromContext(ctx)
Expand All @@ -79,12 +79,16 @@ func (s *Service) Reconcile(ctx context.Context, ing *networkingv1.Ingress, clas

desiredIngresses, desiredDist, err := s.desiredState(ctx, reconciling)
if err != nil {
return fmt.Errorf("computing desired state: %v", err)
return s.handleFailure(fmt.Errorf("computing desired state: %v", err), ing)
}

if err := s.validateCreation(desiredDist, ing); err != nil {
return s.handleFailure(err, ing)
}

cdnStatus, err := s.fetchOrGenerateCDNStatus(desiredIngresses, desiredDist)
if err != nil {
return err
return s.handleFailure(fmt.Errorf("validating creation: %v", err), ing)
}

errs := &multierror.Error{}
Expand Down Expand Up @@ -115,6 +119,18 @@ func (s *Service) Reconcile(ctx context.Context, ing *networkingv1.Ingress, clas
return s.handleResult(ing, cdnStatus, errs)
}

func (s *Service) validateCreation(desiredDist Distribution, ing *networkingv1.Ingress) error {
if desiredDist.Exists() || desiredDist.IsEmpty() || ing.DeletionTimestamp != nil {
return nil
}

if !s.Config.IsCreationAllowed(ing) {
return errors.New("creation of new CloudFront distributions is blocked")
}

return nil
}

func (s *Service) validateIngress(ing *networkingv1.Ingress) error {
if df := k8s.UsedDeprecatedFields(ing); len(df) > 0 {
s.Recorder.Eventf(
Expand Down
44 changes: 44 additions & 0 deletions internal/cloudfront/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ import (
"testing"

"github.com/stretchr/testify/suite"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/Gympass/cdn-origin-controller/internal/config"
)

func TestRunCloudFrontServiceTestSuite(t *testing.T) {
Expand Down Expand Up @@ -70,3 +74,43 @@ func (s *CloudFrontServiceTestSuite) Test_getDeletions() {
s.Equal(tc.want, getDeletions(tc.desired, tc.current), "test: %s", tc.name)
}
}

func (s *CloudFrontServiceTestSuite) Test_validateCreation_IngressesBeingDeletedReturnNoError() {
ing := &networkingv1.Ingress{}
ing.SetDeletionTimestamp(&metav1.Time{})

svc := Service{
Config: config.Config{
IsCreateBlocked: true,
},
}

s.NoError(svc.validateCreation(Distribution{}, ing))
}

func (s *CloudFrontServiceTestSuite) Test_validateCreation_DistributionsBeingDeletedReturnNoError() {
ing := &networkingv1.Ingress{}

svc := Service{
Config: config.Config{
IsCreateBlocked: true,
},
}

s.NoError(svc.validateCreation(Distribution{}, ing))
}

func (s *CloudFrontServiceTestSuite) Test_validateCreation_ExistingDistributionsReturnNoError() {
ing := &networkingv1.Ingress{}

svc := Service{
Config: config.Config{
IsCreateBlocked: true,
},
}
dist := Distribution{
ID: "some id",
}

s.NoError(svc.validateCreation(dist, ing))
}
Loading

0 comments on commit 1a96332

Please sign in to comment.