Skip to content

Add Azure Blob and ADLS support#1279

Open
ddl-ebrown wants to merge 1 commit intofalcosecurity:masterfrom
dominodatalab:azure-blob-alds-support-upstream
Open

Add Azure Blob and ADLS support#1279
ddl-ebrown wants to merge 1 commit intofalcosecurity:masterfrom
dominodatalab:azure-blob-alds-support-upstream

Conversation

@ddl-ebrown
Copy link

@ddl-ebrown ddl-ebrown commented Nov 18, 2025

First take on adding Azure Blob and ADLS Gen 2 write support as backends for sidekick. We're testing this internally right now to make sure everything works as expected, since there are no tests in this repo that could properly vet things.

What type of PR is this?

/kind feature

/area outputs

What this PR does / why we need it:

  • Azure supports two different types of blob storage:

    • Blob
    • ADLS Gen2
  • The setup and configuration of these alternatives varies, as do the Azure SDKs used to access them.

    Provide support for both of these options to sidekick

Which issue(s) this PR fixes:

Fixes # 1209

Special notes for your reviewer:

@poiana poiana added kind/feature New feature or request dco-signoff: no labels Nov 18, 2025
@poiana
Copy link

poiana commented Nov 18, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: ddl-ebrown
Once this PR has been reviewed and has the lgtm label, please assign fjogeleit for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@poiana poiana requested review from Issif and leogr November 18, 2025 17:57
@poiana poiana added the size/L label Nov 18, 2025
 - Azure supports two different types of blob storage:

   * Blob
   * ADLS Gen2

 - The setup and configuration of these alternatives varies, as do the
   Azure SDKs used to access them.

   Provide support for both of these options to sidekick

Signed-off-by: ddl-ebrown <ethan.brown@dominodatalab.com>
@ddl-ebrown ddl-ebrown force-pushed the azure-blob-alds-support-upstream branch from 4da5fd0 to 6b9a0d0 Compare November 18, 2025 19:31
@poiana
Copy link

poiana commented Feb 16, 2026

Issues go stale after 90d of inactivity.

Mark the issue as fresh with /remove-lifecycle stale.

Stale issues rot after an additional 30d of inactivity and eventually close.

If this issue is safe to close now please do so with /close.

Provide feedback via https://github.com/falcosecurity/community.

/lifecycle stale

@ddl-ebrown
Copy link
Author

/remove-lifecycle stale

Copy link
Member

@leogr leogr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ddl-ebrown

Thanks for this PR and sorry for the long delay.

I reviewed this PR and found some issues (see my suggestions below).

Moreover, every output has its defaults set via v.SetDefault(...) and its MinimumPriority validated via checkPriority() in config.go.

This is missing for Blob/ADLS configs.

You should add something like the following near the other Azure defaults:

  v.SetDefault("Azure.Blob.Account", "")
  v.SetDefault("Azure.Blob.Prefix", "falco")
  v.SetDefault("Azure.Blob.Container", "")
  v.SetDefault("Azure.Blob.MinimumPriority", "")

  v.SetDefault("Azure.ADLS.Account", "")
  v.SetDefault("Azure.ADLS.Prefix", "falco")
  v.SetDefault("Azure.ADLS.Container", "")
  v.SetDefault("Azure.ADLS.MinimumPriority", "")

And validation near the other checkPriority calls:

  c.Azure.Blob.MinimumPriority = checkPriority(c.Azure.Blob.MinimumPriority)
  c.Azure.ADLS.MinimumPriority = checkPriority(c.Azure.ADLS.MinimumPriority)

if err != nil {
c.setBlobErrorMetrics()
utils.Log(utils.ErrorLvl, c.OutputType+" Blob",
fmt.Sprintf("Error with acccount %s: %v", serviceURL, err))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fmt.Sprintf("Error with acccount %s: %v", serviceURL, err))
fmt.Sprintf("Error with account %s: %v", serviceURL, err))

attribute.String("status", Error)).Inc()
}

func (c *Client) UploadBlob(falcopayload types.FalcoPayload) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every output function in the codebase starts by incrementing the Total counter (e.g., EventHubPost at line 37 does c.Stats.AzureEventHub.Add(Total, 1)). Please add at the top of the function: c.Stats.AzureBlob.Add(Total, 1)

Same for UploadADLS: c.Stats.AzureADLS.Add(Total, 1)

prefix = c.Config.Azure.Blob.Prefix
}

serviceURL := fmt.Sprintf("https://%s.dfs.core.windows.net/", c.Config.Azure.Blob.Account)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be https://%s.blob.core.windows.net/ ?


// upload the file to the specified container with the specified blob name
// TODO: should any part of the response be validated here? aws s3 client performs a few checks
_, err = client.UploadStream(context.TODO(), c.Config.Azure.Blob.Container, key, bytes.NewReader(f), nil)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without a timeout, a hanging upload will block the goroutine indefinitely. Please add a timeout to this and UploadADLS as well

c.PromStats.Outputs.With(map[string]string{"destination": "azdatalake", "status": Error}).Inc()
c.OTLPMetrics.Outputs.With(attribute.String("destination", "azdatalake"),
attribute.String("status", Error)).Inc()
utils.Log(utils.ErrorLvl, c.OutputType+" S3", err.Error())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
utils.Log(utils.ErrorLvl, c.OutputType+" S3", err.Error())
utils.Log(utils.ErrorLvl, c.OutputType+" Blob", err.Error())

}

go c.CountMetric("outputs", 1, []string{"output:azblob", "status:ok"})
c.PromStats.Outputs.With(map[string]string{"destination": "azblob", "status": "ok"}).Inc()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
c.PromStats.Outputs.With(map[string]string{"destination": "azblob", "status": "ok"}).Inc()
c.PromStats.Outputs.With(map[string]string{"destination": "azblob", "status": OK}).Inc()

if err != nil {
c.setADLSErrorMetrics()
utils.Log(utils.ErrorLvl, c.OutputType+" ADLS Gen2 Blob",
fmt.Sprintf("Error with acccount %s: %v", serviceURL, err))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fmt.Sprintf("Error with acccount %s: %v", serviceURL, err))
fmt.Sprintf("Error with account %s: %v", serviceURL, err))

}

go c.CountMetric("outputs", 1, []string{"output:azdatalake", "status:ok"})
c.PromStats.Outputs.With(map[string]string{"destination": "azdatalake", "status": "ok"}).Inc()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
c.PromStats.Outputs.With(map[string]string{"destination": "azdatalake", "status": "ok"}).Inc()
c.PromStats.Outputs.With(map[string]string{"destination": "azdatalake", "status": OK}).Inc()

go azureClient.EventHubPost(falcopayload)
}

if config.Azure.Blob.Container != "" && (falcopayload.Priority >= types.Priority(config.Azure.Blob.MinimumPriority) || falcopayload.Rule == testRule) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The azureClient is only created in main.go when config.Azure.EventHub.Name != "".

If a user configures only Blob or only ADLS (without EventHub), azureClient will be nil, and these lines will panic with a nil pointer dereference.

The initialization in main.go needs to be updated so azureClient is also created when config.Azure.Blob.Container != "" or config.Azure.ADLS.Container != "". See how awsClient is created when any AWS sub-service is configured.

Also, EnabledOutputs needs to be appended for each enabled sub-service (e.g., "AzureBlob", "AzureADLS")

Comment on lines +921 to +922
AzureBlob *expvar.Map
AzureADLS *expvar.Map
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AzureBlob and AzureADLS should be initialized in getInitStats() in stats.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants