Skip to content
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

[filebeat][httpjson] Add google.jwt_json option to httpjson input #31750

Merged
merged 9 commits into from
Jun 1, 2022
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ https://github.com/elastic/beats/compare/v8.2.0\...main[Check the HEAD diff]
- Change threatintel module from beta to GA. {pull}31693[31693]
- Add template helper function for hashing strings. {issue}31613[31613] {pull}31630[31630]
- Add extended okta.debug_context.debug_data handling. {pull}31676[31676]
- Add `auth.oauth2.google.jwt_json` option to `httpjson` input. {pull}31750[31750]

*Auditbeat*

Expand Down
12 changes: 11 additions & 1 deletion x-pack/filebeat/docs/inputs/input-httpjson.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,20 @@ NOTE: Only one of the credentials settings can be set at once. If none is provid
default credentials from the environment will be attempted via ADC. For more information about
how to provide Google credentials, please refer to https://cloud.google.com/docs/authentication.

[float]
==== `auth.oauth2.google.jwt_json`

The JWT Account Key file as raw JSON.

NOTE: Only one of the credentials settings can be set at once. If none is provided, loading
default credentials from the environment will be attempted via ADC. For more information about
how to provide Google credentials, please refer to https://cloud.google.com/docs/authentication.

[float]
==== `auth.oauth2.google.delegated_account`

Email of the delegated account used to create the credentials (usually an admin).
Email of the delegated account used to create the credentials (usually an admin). Used in combination
with `auth.oauth2.google.jwt_file` or `auth.oauth2.google.jwt_json`.

[[request-parameters]]
[float]
Expand Down
31 changes: 28 additions & 3 deletions x-pack/filebeat/input/httpjson/config_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ type oAuth2Config struct {
GoogleCredentialsFile string `config:"google.credentials_file"`
GoogleCredentialsJSON common.JSONBlob `config:"google.credentials_json"`
GoogleJWTFile string `config:"google.jwt_file"`
GoogleJWTJSON common.JSONBlob `config:"google.jwt_json"`
GoogleDelegatedAccount string `config:"google.delegated_account"`

// microsoft azure specific
Expand Down Expand Up @@ -147,8 +148,8 @@ func (o *oAuth2Config) client(ctx context.Context, client *http.Client) (*http.C
case oAuth2ProviderAzure:
return o.clientCredentialsGrant(ctx, client), nil
case oAuth2ProviderGoogle:
if o.GoogleJWTFile != "" {
cfg, err := google.JWTConfigFromJSON(o.GoogleCredentialsJSON, o.Scopes...)
if len(o.GoogleJWTJSON) > 0 {
marc-gr marked this conversation as resolved.
Show resolved Hide resolved
cfg, err := google.JWTConfigFromJSON(o.GoogleJWTJSON, o.Scopes...)
if err != nil {
return nil, fmt.Errorf("oauth2 client: error loading jwt credentials: %w", err)
}
Expand Down Expand Up @@ -250,7 +251,12 @@ func (o *oAuth2Config) validateGoogleProvider() error {

// jwt_file
if o.GoogleJWTFile != "" {
return o.populateCredentialsJSONFromFile(o.GoogleJWTFile)
return o.populateJWTJSONFromFile(o.GoogleJWTFile)
}

// jwt_json
if len(o.GoogleJWTJSON) > 0 {
marc-gr marked this conversation as resolved.
Show resolved Hide resolved
return nil
}

// Application Default Credentials (ADC)
Expand Down Expand Up @@ -282,6 +288,25 @@ func (o *oAuth2Config) populateCredentialsJSONFromFile(file string) error {
return nil
}

func (o *oAuth2Config) populateJWTJSONFromFile(file string) error {
marc-gr marked this conversation as resolved.
Show resolved Hide resolved
if _, err := os.Stat(file); os.IsNotExist(err) {
marc-gr marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Errorf("the file %q cannot be found", file)
}

credBytes, err := ioutil.ReadFile(file)
marc-gr marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return fmt.Errorf("the file %q cannot be read", file)
}

if !json.Valid(credBytes) {
return fmt.Errorf("the file %q does not contain valid JSON", file)
}

o.GoogleJWTJSON = credBytes

return nil
}

func (o *oAuth2Config) validateAzureProvider() error {
if o.TokenURL == "" && o.AzureTenantID == "" {
return errors.New("at least one of token_url or tenant_id must be provided")
Expand Down
25 changes: 25 additions & 0 deletions x-pack/filebeat/input/httpjson/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,21 @@ func TestConfigOauth2Validation(t *testing.T) {
},
},
},
{
name: "google must work if jwt_json is correct",
input: map[string]interface{}{
"auth.oauth2": map[string]interface{}{
"provider": "google",
"google.jwt_json": `{
"type": "service_account",
"project_id": "foo",
"private_key_id": "x",
"client_email": "foo@bar.com",
"client_id": "0"
}`,
},
},
},
{
name: "google must work if credentials_json is correct",
input: map[string]interface{}{
Expand All @@ -349,6 +364,16 @@ func TestConfigOauth2Validation(t *testing.T) {
},
},
},
{
name: "google must fail if jwt_json is not a valid JSON",
expectedErr: "the field can't be converted to valid JSON accessing 'auth.oauth2.google.jwt_json'",
input: map[string]interface{}{
"auth.oauth2": map[string]interface{}{
"provider": "google",
"google.jwt_json": `invalid`,
},
},
},
{
name: "google must fail if the provided credentials file is not a valid JSON",
expectedErr: "the file \"./testdata/invalid_credentials.json\" does not contain valid JSON accessing 'auth.oauth2'",
Expand Down