Skip to content

Commit c8b1d12

Browse files
Support sub-CA to be activated into staged state (#12162) (#8560)
[upstream:3cca7aa245ba4e600cbe9f1cb23b316fb5361845] Signed-off-by: Modular Magician <[email protected]>
1 parent e3ef94f commit c8b1d12

File tree

3 files changed

+167
-4
lines changed

3 files changed

+167
-4
lines changed

Diff for: .changelog/12162.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note: enhancement
2+
privateca: added support for sub-CA to be activated into STAGED state
3+
```

Diff for: google-beta/services/privateca/resource_privateca_certificate_authority.go

-4
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ func resourcePrivateCaCACustomDiff(_ context.Context, diff *schema.ResourceDiff,
3939
_, new := diff.GetChange("desired_state")
4040

4141
if tpgresource.IsNewResource(diff) {
42-
if diff.Get("type").(string) == "SUBORDINATE" {
43-
return fmt.Errorf("`desired_state` can not be specified when creating a SUBORDINATE CA")
44-
}
4542
if new.(string) != "STAGED" && new.(string) != "ENABLED" {
4643
return fmt.Errorf("`desired_state` can only be set to `STAGED` or `ENABLED` when creating a new CA")
4744
}
@@ -1004,7 +1001,6 @@ func resourcePrivatecaCertificateAuthorityCreate(d *schema.ResourceData, meta in
10041001

10051002
// Enable the CA if `desired_state` is unspecified or specified as `ENABLED`.
10061003
if p, ok := d.GetOk("desired_state"); !ok || p.(string) == "ENABLED" {
1007-
// Skip enablement on SUBORDINATE CA for backward compatible.
10081004
if staged {
10091005
if err := enableCA(config, d, project, billingProject, userAgent); err != nil {
10101006
return fmt.Errorf("Error enabling CertificateAuthority: %v", err)

Diff for: google-beta/services/privateca/resource_privateca_certificate_authority_test.go

+164
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,33 @@ func TestAccPrivatecaCertificateAuthority_subordinateCaActivatedByFirstPartyIssu
149149
})
150150
}
151151

152+
func TestAccPrivatecaCertificateAuthority_subordinateCaActivatedByFirstPartyIssuerOnCreationInStagedState(t *testing.T) {
153+
t.Parallel()
154+
acctest.SkipIfVcr(t)
155+
156+
random_suffix := acctest.RandString(t, 10)
157+
context := map[string]interface{}{
158+
"root_location": "us-central1",
159+
"sub_location": "australia-southeast1",
160+
"random_suffix": random_suffix,
161+
}
162+
163+
resourceName := "google_privateca_certificate_authority.sub-1"
164+
acctest.VcrTest(t, resource.TestCase{
165+
PreCheck: func() { acctest.AccTestPreCheck(t) },
166+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
167+
CheckDestroy: testAccCheckPrivatecaCertificateAuthorityDestroyProducer(t),
168+
Steps: []resource.TestStep{
169+
{
170+
Config: testAccPrivatecaCertificateAuthority_privatecaCertificateAuthoritySubordinateStagedWithFirstPartyIssuer(context),
171+
Check: resource.ComposeTestCheckFunc(
172+
resource.TestCheckResourceAttr(resourceName, "state", "STAGED"),
173+
),
174+
},
175+
},
176+
})
177+
}
178+
152179
func testAccPrivatecaCertificateAuthority_privatecaCertificateAuthorityBasicRoot(context map[string]interface{}) string {
153180
return acctest.Nprintf(`
154181
resource "google_privateca_certificate_authority" "default" {
@@ -450,3 +477,140 @@ resource "google_privateca_certificate_authority" "sub-1" {
450477
}
451478
`, context)
452479
}
480+
481+
// testAccPrivatecaCertificateAuthority_privatecaCertificateAuthoritySubordinateStagedWithFirstPartyIssuer provides a config
482+
// which contains
483+
// * A CaPool for root CA
484+
// * A root CA
485+
// * A CaPool for sub CA
486+
// * A subordinate CA which should be activated by the above root CA
487+
func testAccPrivatecaCertificateAuthority_privatecaCertificateAuthoritySubordinateStagedWithFirstPartyIssuer(context map[string]interface{}) string {
488+
return acctest.Nprintf(`
489+
resource "google_privateca_ca_pool" "root-pool" {
490+
name = "root-pool-%{random_suffix}"
491+
location = "%{root_location}"
492+
tier = "ENTERPRISE"
493+
publishing_options {
494+
publish_ca_cert = true
495+
publish_crl = true
496+
}
497+
}
498+
499+
resource "google_privateca_certificate_authority" "root-1" {
500+
pool = google_privateca_ca_pool.root-pool.name
501+
certificate_authority_id = "tf-test-my-certificate-authority-root-%{random_suffix}"
502+
location = "%{root_location}"
503+
config {
504+
subject_config {
505+
subject {
506+
organization = "HashiCorp"
507+
common_name = "my-certificate-authority"
508+
}
509+
subject_alt_name {
510+
dns_names = ["hashicorp.com"]
511+
}
512+
}
513+
x509_config {
514+
ca_options {
515+
is_ca = true
516+
max_issuer_path_length = 10
517+
}
518+
key_usage {
519+
base_key_usage {
520+
digital_signature = true
521+
content_commitment = true
522+
key_encipherment = false
523+
data_encipherment = true
524+
key_agreement = true
525+
cert_sign = true
526+
crl_sign = true
527+
decipher_only = true
528+
}
529+
extended_key_usage {
530+
server_auth = true
531+
client_auth = false
532+
email_protection = true
533+
code_signing = true
534+
time_stamping = true
535+
}
536+
}
537+
}
538+
}
539+
lifetime = "86400s"
540+
key_spec {
541+
algorithm = "RSA_PKCS1_4096_SHA256"
542+
}
543+
544+
// Disable CA deletion related safe checks for easier cleanup.
545+
deletion_protection = false
546+
skip_grace_period = true
547+
ignore_active_certificates_on_deletion = true
548+
}
549+
550+
resource "google_privateca_ca_pool" "sub-pool" {
551+
name = "sub-pool-%{random_suffix}"
552+
location = "%{sub_location}"
553+
tier = "ENTERPRISE"
554+
publishing_options {
555+
publish_ca_cert = true
556+
publish_crl = true
557+
}
558+
}
559+
560+
resource "google_privateca_certificate_authority" "sub-1" {
561+
pool = google_privateca_ca_pool.sub-pool.name
562+
certificate_authority_id = "tf-test-my-certificate-authority-sub-%{random_suffix}"
563+
location = "%{sub_location}"
564+
desired_state = "STAGED"
565+
subordinate_config {
566+
certificate_authority = google_privateca_certificate_authority.root-1.name
567+
}
568+
config {
569+
subject_config {
570+
subject {
571+
organization = "HashiCorp"
572+
common_name = "my-certificate-authority"
573+
}
574+
subject_alt_name {
575+
dns_names = ["hashicorp.com"]
576+
}
577+
}
578+
x509_config {
579+
ca_options {
580+
is_ca = true
581+
max_issuer_path_length = 10
582+
}
583+
key_usage {
584+
base_key_usage {
585+
digital_signature = true
586+
content_commitment = true
587+
key_encipherment = false
588+
data_encipherment = true
589+
key_agreement = true
590+
cert_sign = true
591+
crl_sign = true
592+
decipher_only = true
593+
}
594+
extended_key_usage {
595+
server_auth = true
596+
client_auth = false
597+
email_protection = true
598+
code_signing = true
599+
time_stamping = true
600+
}
601+
}
602+
}
603+
}
604+
lifetime = "86400s"
605+
key_spec {
606+
algorithm = "RSA_PKCS1_4096_SHA256"
607+
}
608+
type = "SUBORDINATE"
609+
610+
// Disable CA deletion related safe checks for easier cleanup.
611+
deletion_protection = false
612+
skip_grace_period = true
613+
ignore_active_certificates_on_deletion = true
614+
}
615+
`, context)
616+
}

0 commit comments

Comments
 (0)