Skip to content

Commit

Permalink
Added oidcToken to pubsub api.
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
Tony-Proum authored and modular-magician committed Oct 19, 2019
1 parent 1ed9f43 commit 20e8c9a
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 12 deletions.
83 changes: 83 additions & 0 deletions google/resource_pubsub_subscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,23 @@ func resourcePubsubSubscription() *schema.Resource {
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"oidc_token": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"service_account_email": {
Type: schema.TypeString,
Required: true,
},
"audience": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
},
},
},
Expand Down Expand Up @@ -449,12 +466,37 @@ func flattenPubsubSubscriptionPushConfig(v interface{}, d *schema.ResourceData)
return nil
}
transformed := make(map[string]interface{})
transformed["oidc_token"] =
flattenPubsubSubscriptionPushConfigOidcToken(original["oidcToken"], d)
transformed["push_endpoint"] =
flattenPubsubSubscriptionPushConfigPushEndpoint(original["pushEndpoint"], d)
transformed["attributes"] =
flattenPubsubSubscriptionPushConfigAttributes(original["attributes"], d)
return []interface{}{transformed}
}
func flattenPubsubSubscriptionPushConfigOidcToken(v interface{}, d *schema.ResourceData) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["service_account_email"] =
flattenPubsubSubscriptionPushConfigOidcTokenServiceAccountEmail(original["serviceAccountEmail"], d)
transformed["audience"] =
flattenPubsubSubscriptionPushConfigOidcTokenAudience(original["audience"], d)
return []interface{}{transformed}
}
func flattenPubsubSubscriptionPushConfigOidcTokenServiceAccountEmail(v interface{}, d *schema.ResourceData) interface{} {
return v
}

func flattenPubsubSubscriptionPushConfigOidcTokenAudience(v interface{}, d *schema.ResourceData) interface{} {
return v
}

func flattenPubsubSubscriptionPushConfigPushEndpoint(v interface{}, d *schema.ResourceData) interface{} {
return v
}
Expand Down Expand Up @@ -558,6 +600,13 @@ func expandPubsubSubscriptionPushConfig(v interface{}, d TerraformResourceData,
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedOidcToken, err := expandPubsubSubscriptionPushConfigOidcToken(original["oidc_token"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedOidcToken); val.IsValid() && !isEmptyValue(val) {
transformed["oidcToken"] = transformedOidcToken
}

transformedPushEndpoint, err := expandPubsubSubscriptionPushConfigPushEndpoint(original["push_endpoint"], d, config)
if err != nil {
return nil, err
Expand All @@ -575,6 +624,40 @@ func expandPubsubSubscriptionPushConfig(v interface{}, d TerraformResourceData,
return transformed, nil
}

func expandPubsubSubscriptionPushConfigOidcToken(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedServiceAccountEmail, err := expandPubsubSubscriptionPushConfigOidcTokenServiceAccountEmail(original["service_account_email"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedServiceAccountEmail); val.IsValid() && !isEmptyValue(val) {
transformed["serviceAccountEmail"] = transformedServiceAccountEmail
}

transformedAudience, err := expandPubsubSubscriptionPushConfigOidcTokenAudience(original["audience"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedAudience); val.IsValid() && !isEmptyValue(val) {
transformed["audience"] = transformedAudience
}

return transformed, nil
}

func expandPubsubSubscriptionPushConfigOidcTokenServiceAccountEmail(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandPubsubSubscriptionPushConfigOidcTokenAudience(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandPubsubSubscriptionPushConfigPushEndpoint(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}
Expand Down
57 changes: 45 additions & 12 deletions google/resource_pubsub_subscription_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,30 @@ func TestAccPubsubSubscription_update(t *testing.T) {
})
}

func TestAccPubsubSubscription_push(t *testing.T) {
t.Parallel()

topicFoo := fmt.Sprintf("tf-test-topic-foo-%s", acctest.RandString(10))
subscription := fmt.Sprintf("projects/%s/subscriptions/tf-test-topic-foo-%s", getTestProjectFromEnv(), acctest.RandString(10))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckPubsubSubscriptionDestroy,
Steps: []resource.TestStep{
{
Config: testAccPubsubSubscription_push(topicFoo, subscription),
},
{
ResourceName: "google_pubsub_subscription.foo",
ImportStateId: subscription,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccPubsubSubscription_emptyTTL(topic, subscription string) string {
return fmt.Sprintf(`
resource "google_pubsub_topic" "foo" {
Expand All @@ -123,18 +147,27 @@ resource "google_pubsub_subscription" "foo" {
`, topic, subscription)
}

// TODO: Add acceptance test for push delivery.
//
// Testing push endpoints is tricky for the following reason:
// - You need a publicly accessible HTTPS server to handle POST requests in order to receive push messages.
// - The server must present a valid SSL certificate signed by a certificate authority
// - The server must be routable by DNS.
// - You also need to validate that you own the domain (or have equivalent access to the endpoint).
// - Finally, you must register the endpoint domain with the GCP project.
//
// An easy way to test this would be to create an App Engine Hello World app. With AppEngine, SSL certificate, DNS and domain registry is handled for us.
// App Engine is not yet supported by Terraform but once it is, it will provide an easy path to testing push configs.
// Another option would be to use Cloud Functions once Terraform support is added.
func testAccPubsubSubscription_push(topicFoo string, subscription string) string {
return fmt.Sprintf(`
data "google_project" "project" {}
resource "google_pubsub_topic" "foo" {
name = "%s"
}
resource "google_pubsub_subscription" "foo" {
name = "%s"
topic = "${google_pubsub_topic.foo.name}"
ack_deadline_seconds = 10
push_config {
push_endpoint = "https://${data.google_project.project.project_id}.appspot.com"
oidc_token {
service_account_email = "${google_service_account.service_account.email}"
}
}
}
`, topicFoo, subscription)
}

func testAccPubsubSubscription_fullName(topic, subscription, label string, deadline int) string {
return fmt.Sprintf(`
Expand Down
24 changes: 24 additions & 0 deletions website/docs/r/pubsub_subscription.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ The following arguments are supported:

The `push_config` block supports:

* `oidc_token` -
(Optional)
If specified, Pub/Sub will generate and attach an OIDC JWT token as
an Authorization header in the HTTP request for every pushed message. Structure is documented below.

* `push_endpoint` -
(Required)
A URL locating the endpoint to which messages should be pushed.
Expand Down Expand Up @@ -212,6 +217,25 @@ The `push_config` block supports:
- v1beta1: uses the push format defined in the v1beta1 Pub/Sub API.
- v1 or v1beta2: uses the push format defined in the v1 Pub/Sub API.


The `oidc_token` block supports:

* `service_account_email` -
(Required)
Service account email to be used for generating the OIDC token.
The caller (for subscriptions.create, subscriptions.patch, and
subscriptions.modifyPushConfig RPCs) must have the
iam.serviceAccounts.actAs permission for the service account.

* `audience` -
(Optional)
Audience to be used when generating OIDC token. The audience claim
identifies the recipients that the JWT is intended for. The audience
value is a single case-sensitive string. Having multiple values (array)
for the audience field is not supported. More info about the OIDC JWT
token audience here: https://tools.ietf.org/html/rfc7519#section-4.1.3
Note: if not specified, the Push endpoint URL will be used.

The `expiration_policy` block supports:

* `ttl` -
Expand Down

0 comments on commit 20e8c9a

Please sign in to comment.