-
-
Notifications
You must be signed in to change notification settings - Fork 359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add acmpa ✨ #201
Add acmpa ✨ #201
Conversation
a9444c2
to
d9566af
Compare
@brikis98 @yorinasub17 The tests work, and this PR is good to review (I cannot update the description or title) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your contribution! I had a few comments, most of them nits from defensive coding.
The biggest question mark for me prior to merging this in is how much it will cost to run the automated tests. Depending on that answer, we will need to come up with some strategy to limit the costs for us.
aws/acmpca.go
Outdated
result, err := svc.ListCertificateAuthorities(&acmpca.ListCertificateAuthoritiesInput{}) | ||
if err != nil { | ||
return nil, errors.WithStackTrace(err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should handle pagination.
aws/acmpca.go
Outdated
var arns []*string | ||
for _, ca := range result.CertificateAuthorities { | ||
// one can only delete CAs if they are 'ACTIVE' or 'DISABLED' | ||
isCandidateForDeletion := *ca.Status == acmpca.CertificateAuthorityStatusActive || *ca.Status == acmpca.CertificateAuthorityStatusDisabled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use aws.StringValue
to safe dereference pointers.
aws/acmpca.go
Outdated
if !isCandidateForDeletion { | ||
continue | ||
} | ||
if excludeAfter.After(*ca.CreatedAt) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use aws.TimeValue
to safe dereference the pointer.
) | ||
|
||
// getAllACMPCA returns a list of all arns of ACMPCA, which can be deleted. | ||
func getAllACMPCA(session *session.Session, region string, excludeAfter time.Time) ([]*string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this isn't implementing the config file based name filter using regexes. You need to plumb the config file through to here so that it properly filters out those that don't match the regex.
aws/acmpca.go
Outdated
for _, arn := range arns { | ||
logging.Logger.Infof("Setting status to 'DISABLED' for ACMPCA %s in region %s", *arn, *session.Config.Region) | ||
if _, updateStatusErr := svc.UpdateCertificateAuthority(&acmpca.UpdateCertificateAuthorityInput{ | ||
CertificateAuthorityArn: arn, | ||
Status: aws.String(acmpca.CertificateAuthorityStatusDisabled), | ||
}); updateStatusErr != nil { | ||
logging.Logger.Errorf("[Failed] %s", updateStatusErr) | ||
continue | ||
} | ||
logging.Logger.Infof("Did set status to 'DISABLED' for ACMPCA: %s in region %s", *arn, *session.Config.Region) | ||
|
||
if _, deleteErr := svc.DeleteCertificateAuthority(&acmpca.DeleteCertificateAuthorityInput{ | ||
CertificateAuthorityArn: arn, | ||
// the range is 7 to 30 days. | ||
// since cloud-nuke should not be used in production, | ||
// we assume that the minimum (7 days) is fine. | ||
PermanentDeletionTimeInDays: aws.Int64(7), | ||
}); deleteErr != nil { | ||
logging.Logger.Errorf("[Failed] %s", deleteErr) | ||
continue | ||
} | ||
deletedARNs = append(deletedARNs, arn) | ||
logging.Logger.Infof("Deleted ACMPCA: %s", *arn) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is using single API calls to delete each one, this should be refactored to use goroutines so that multiple requests can be made concurrently. See the secrets manager deletion routine for reference: https://github.com/gruntwork-io/cloud-nuke/blob/master/aws/secrets_manager.go#L70-L89
) | ||
|
||
// createTestACMPCA will create am ACMPCA and return its ARN. | ||
func createTestACMPCA(t *testing.T, session *session.Session, name string) *string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sanity check: Do you have a sense on how much it would cost to run this test? It appears that the cost of ACM Private CA is $400 / month, pro rated to the number of X (days or hours?) that it is active. Does that active period include the days it is waiting to be deleted (the 7 day minimum)? If so, that can rack up quickly for us if we are running cloud nuke tests for each PR.
Depending on how much it costs, can you add an environment variable flag so that we can control when we run the tests related to the ACM PCA functionality (and not on every PR)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am currently talking to our AWS Enterprise contact as indeed their documentation and support is not clear on this and racked up a significant amount of money just for starting/stopping a CA.
I will add some environment variable and this test will be opt-in in all cases so you have to make a concious decision to run it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We heard back from our contact. The billing is pro-rated and does reconciliation after 24-48 hours and you only pay for those hours.
Hypothesis from Support-Agent
Hi Jan
It looks like the billing is fluctuating due to the 24-48 hour delay between the billing console and reality. When a certificate is created, the full amount for the month is added to the bill and this only changes to the pro-rated amount after the certificate has been deleted. I'll keep the internal ticket open with the service team just to confirm that this is exactly what is going on. In terms of your other questions, here are the answers:
- How does AWS want to do pricing for short-lived CAs? (i.e. can we enable a testing pipeline or not)
->>>> I will forward this request to the service team and I'll update you as soon as I hear back from them.- Is there an absolute upper service quota for CAs in an account? (I see 200 quoted right now)
->>>> The quota of 200 is the default, and we can request an increase should you require it, but we would need a detailed use case for this request.- Do deleted CAs (with their 7 - 30 day pending period) count towards the service quota?
->>>> Yes, deleted Private CAs count towards the quota until the end of the restoration period.
Answer from AWS PCA Service Team confirming hypothesis from Support-Agent above
Quote
Thank you for your patience. I've just heard back from the team and my original answer about the delay between the billing console and reality is correct. Because the invoice for each month is issued a few days after the end of the month, by the time the bill is issued, everything will have refreshed and the bill will reflect correctly. For the current month, the "real" bill so far is around $7.
For some more context on how we charge for short term PCAs, the team provided the following:
AWS PCA charge customer based on the time period: from the time that CA was created to the time CA was deleted.
Facts:
Customer created 22 CAs in FRA region in July. 1 of them are in free trial.
Customer create CA, and delete them in a short period of time. --> this is fine, nothing wrong.
Customer check bill of July, which is not the final statement. There are delays between customer deleted the CA and the >billing team calculate the bill based on latest data.
If customer check right now, the bill will become about $168.
When customer finally get bill in August, the total charge will be around $8. Unless they created new CAs
Considering this information, the best way to monitor the bill for PCA specifically would be to log the hours and calculate this manually on your side throughout the month.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So how do we think about the pricing here?
If we have this test case and it runs, say, nightly for a month, what sort of fee are we talking? What if we get 20 PRs in this repo, and each one does 20 test runs in a month?
I just want to be extra sure we don't end up with a massive AWS bill as a surprise from adding this new functionality!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brikis98 I think we can go with this for now. @weitzjdevk implemented a feature flag to disable the tests by default. We can merge with that disabled.
Separately, I'll run an experiment to enable that test locally once. Then, we can check how much our bill was for August and make our decision on whether to continually test it or not based on that bill cost. Does that seem reasonable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have this test case and it runs, say, nightly for a month, what sort of fee are we talking? What if we get 20 PRs in this repo, and each one does 20 test runs in a month?
tl;dr: Price per run approx: $0.60
(if you issue a certificate + $0.75
therefore approx $1.50
)
So the rough calculation how this works.
Monthly charge (for CA only): $400
Month has hours: 720
Price (CA) per hour approx. 400/720
approx $ 0.6
Issue a certificate charge: $0.75
Therefore roughly:
Price per run $0.60 + $0.75
approx. $1.50
Timeline (when starting the first day of the month)
- Day1 (first of the month):
$0
- Run it
- Delete it
- Day1 bill:
$0
- Day2 bill:
$400 + 0.75
- Day3 bill:
$400 + 0.75
- Day4 bill:
$400/720 + 0.75
When you do the run in the middle of the month
- Day15 (middle of the month):
$0
- Run it
- Delete it
- Day15 bill:
$0
- Day16 bill (middle of month. Only 15 more days for pro-rating):
$400 * 15 / 30 + 0.75 = $200 + 0.75
- Day17 bill:
$200 + 0.75
- Day18 bill:
$400/720 + 0.75
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have confirmed this cost in our account as well. I think 0.60 per run is a tad bit expensive to be continuously running the tests, but selectively running it everytime this feature changes seems reasonable, so the env var based feature switch is satisfactory.
Could you please have another look. I have addressed your comments in separate commits. |
This adds support to delete AWS ACM Private CAs. Fixes gruntwork-io#200
This also refactors the logic for calculating excludeTime.
Please review, merge. |
@yorinasub17 , @brikis98 I have rebased against the current master. The review comments are incorportated. See the answer from AWS Support how billing works. |
Any update on this? |
@weitzj Sorry for the delay. We are very buried at the moment. Since we don't have a ton of customers using ACM PA, reviewing this is getting deprioritized in favor of things that many customers are using and requesting. We'll get to it as soon as we can. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updates LGTM except for the one nit about the name regex. Can you address that?
In the meantime, I'll go ahead and kick off a build in CI (without enabling ACM), and locally (with enabling ACM). That can give us a sense of how much the ACMPA costs for each test run, and we can use that information to base whether or not we can permanently enable the tests.
aws/acmpca.go
Outdated
aws.StringValue(ca.Arn), | ||
configObj.ACMPCA.IncludeRule.NamesRegExp, | ||
configObj.ACMPCA.ExcludeRule.NamesRegExp, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is checking the names regex against the ARN, which is unintuitive. Is there a way to just get the name out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. I will think about it. You are correct that this does not feel good.
It should be something unique. And the name
is not unique.
What is your plan about the regex
behaviour for other resources? Is this "the final form"? Otherwise I would get rid of the regex in total.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would need your guidance on this. Indeed this would be the ARN and there is nothing better than using the ARN for it. Name does not make much sense for this service.
I could introduce new types?
type Config struct {
....
ACMPCA ResourceTypeARN `yaml:"acmcpa"`
}
type ResourceTypeARN struct {
IncludeRule FilterRuleARN `yaml:"include"`
ExcludeRule FilterRuleARN `yaml:"exclude"`
}
type FilterRuleARN struct {
ARNsRegExp []Expression `yaml:"arns_regex"`
}
Or I could do:
type FilterRule struct {
NamesRegExp []Expression `yaml:"names_regex"`
ARNsRegExp []Expression `yaml:"names_regex"`
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is your plan about the regex behaviour for other resources? Is this "the final form"? Otherwise I would get rid of the regex in total.
This is not the final form, as we plan on supporting tags (something users have requested for other resources). Adding in ARN support or tag support just for ACM PCA makes sense to me, although that would be a lot more work to add considering the potential regressions with other resources.
If it isn't critical for your environment, I might suggest removing the regex filters for now and add that in later as a future feature when we support something that makes more sense, like ARN or tags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright. I have removed the configObj
support (see the latest commit)
aws/acmpca.go
Outdated
logging.Logger.Infof("Setting status to 'DISABLED' for ACMPCA %s in region %s", *arn, region) | ||
if _, updateStatusErr := svc.UpdateCertificateAuthority(&acmpca.UpdateCertificateAuthorityInput{ | ||
CertificateAuthorityArn: arn, | ||
Status: aws.String(acmpca.CertificateAuthorityStatusDisabled), | ||
}); updateStatusErr != nil { | ||
errChan <- updateStatusErr | ||
return | ||
} | ||
logging.Logger.Infof("Did set status to 'DISABLED' for ACMPCA: %s in region %s", *arn, region) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this step necessary? I just tried the test and it failed with:
=== RUN TestListACMPCA
=== PAUSE TestListACMPCA
=== CONT TestListACMPCA
[cloud-nuke] time="2021-08-04T10:47:49-05:00" level=info msg="Random region chosen: eu-north-1"
acmpca_test.go:93:
Error Trace: acmpca_test.go:93
Error: []string{} does not contain "arn:aws:acm-pca:eu-north-1:738755648600:certificate-authority/3cb99176-55e7-427a-9fd7-2a0208d12c98"
Test: TestListACMPCA
[cloud-nuke] time="2021-08-04T10:47:50-05:00" level=info msg="Deleting all ACMPCA in region eu-north-1"
[cloud-nuke] time="2021-08-04T10:47:50-05:00" level=info msg="Setting status to 'DISABLED' for ACMPCA arn:aws:acm-pca:eu-north-1:738755648600:certificate-authority/3cb99176-55e7-427a-9fd7-2a0208d12c98 in region eu-north-1"
[cloud-nuke] time="2021-08-04T10:47:51-05:00" level=error msg="[Failed] InvalidStateException: The certificate authority must be in the ACTIVE or DISABLED state to be updated"
--- FAIL: TestListACMPCA (2.36s)
The PCA was in state Pending Validation
. However, I was able to delete it just fine using the UI, which suggests that it may not be necessary to disable the PCA prior to deleting it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh. Sorry. I will make the listing more smart and test it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the latest commits. Now the tests work as expected. I had to fix a race-condition, where the CA was in a "CREATING" state during test, which one could not see during the test.
Now the "createCA" command waits with retry
until the status is the one we need to actually test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fixed here.
Just a side-note how the terraform-provider-aws does it:
Everything is fixed (see the last commits). |
@yorinasub17 I think everything is fine now. See the latest commits, where I have removed the configObj support. Also the last commit fixes some Do you want me to rebase? squash-merge? Do you do this? |
@yorinasub17 Anything missing? Can we get this merged? Did you check your AWS Bill? |
@weitzj Apologies for the delay here. I've been super swamped with other priorities and haven't been able to come back to this. I hope to get back to this later this week, or next week. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updates LGTM, the tests passed locally! The build failed, but I confirmed it was a fluke, so going to go ahead and merge + release this. Thanks for your patience in the review process!
This PR adds support to delete AWS ACM Private CAs (acmpca).
This needs a bit more testing.
Fixes #200