The azure-native:security:DevOpsConfiguration resource, part of the Pulumi Azure Native provider, configures how Microsoft Defender for Cloud connects to and scans DevOps repositories. This guide focuses on three capabilities: auto-discovery modes, authorization setup, and selective organization onboarding.
DevOps configurations depend on an existing security connector and OAuth authorization from your DevOps platform (GitHub, Azure DevOps, or GitLab). The examples are intentionally small. Combine them with your own security connector and authorization flow.
Enable automatic discovery for current and future repositories
Teams connecting DevOps platforms to Defender for Cloud often want security scanning to apply automatically to all repositories, including those created after onboarding.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const devOpsConfiguration = new azure_native.security.DevOpsConfiguration("devOpsConfiguration", {
properties: {
authorization: {
code: "00000000000000000000",
},
autoDiscovery: azure_native.security.AutoDiscovery.Enabled,
},
resourceGroupName: "myRg",
securityConnectorName: "mySecurityConnectorName",
});
import pulumi
import pulumi_azure_native as azure_native
dev_ops_configuration = azure_native.security.DevOpsConfiguration("devOpsConfiguration",
properties={
"authorization": {
"code": "00000000000000000000",
},
"auto_discovery": azure_native.security.AutoDiscovery.ENABLED,
},
resource_group_name="myRg",
security_connector_name="mySecurityConnectorName")
package main
import (
security "github.com/pulumi/pulumi-azure-native-sdk/security/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := security.NewDevOpsConfiguration(ctx, "devOpsConfiguration", &security.DevOpsConfigurationArgs{
Properties: &security.DevOpsConfigurationPropertiesArgs{
Authorization: &security.AuthorizationArgs{
Code: pulumi.String("00000000000000000000"),
},
AutoDiscovery: pulumi.String(security.AutoDiscoveryEnabled),
},
ResourceGroupName: pulumi.String("myRg"),
SecurityConnectorName: pulumi.String("mySecurityConnectorName"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var devOpsConfiguration = new AzureNative.Security.DevOpsConfiguration("devOpsConfiguration", new()
{
Properties = new AzureNative.Security.Inputs.DevOpsConfigurationPropertiesArgs
{
Authorization = new AzureNative.Security.Inputs.AuthorizationArgs
{
Code = "00000000000000000000",
},
AutoDiscovery = AzureNative.Security.AutoDiscovery.Enabled,
},
ResourceGroupName = "myRg",
SecurityConnectorName = "mySecurityConnectorName",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.security.DevOpsConfiguration;
import com.pulumi.azurenative.security.DevOpsConfigurationArgs;
import com.pulumi.azurenative.security.inputs.DevOpsConfigurationPropertiesArgs;
import com.pulumi.azurenative.security.inputs.AuthorizationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var devOpsConfiguration = new DevOpsConfiguration("devOpsConfiguration", DevOpsConfigurationArgs.builder()
.properties(DevOpsConfigurationPropertiesArgs.builder()
.authorization(AuthorizationArgs.builder()
.code("00000000000000000000")
.build())
.autoDiscovery("Enabled")
.build())
.resourceGroupName("myRg")
.securityConnectorName("mySecurityConnectorName")
.build());
}
}
resources:
devOpsConfiguration:
type: azure-native:security:DevOpsConfiguration
properties:
properties:
authorization:
code: '00000000000000000000'
autoDiscovery: Enabled
resourceGroupName: myRg
securityConnectorName: mySecurityConnectorName
When autoDiscovery is set to Enabled, Defender for Cloud continuously monitors your DevOps platform and automatically onboards new repositories as they’re created. The authorization code establishes the OAuth connection between Defender for Cloud and your DevOps platform. The securityConnectorName links this configuration to an existing security connector resource.
Scan only existing repositories without auto-discovery
Some organizations prefer explicit control over which repositories are scanned, disabling automatic enrollment for new repositories.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const devOpsConfiguration = new azure_native.security.DevOpsConfiguration("devOpsConfiguration", {
properties: {
authorization: {
code: "00000000000000000000",
},
autoDiscovery: azure_native.security.AutoDiscovery.Disabled,
},
resourceGroupName: "myRg",
securityConnectorName: "mySecurityConnectorName",
});
import pulumi
import pulumi_azure_native as azure_native
dev_ops_configuration = azure_native.security.DevOpsConfiguration("devOpsConfiguration",
properties={
"authorization": {
"code": "00000000000000000000",
},
"auto_discovery": azure_native.security.AutoDiscovery.DISABLED,
},
resource_group_name="myRg",
security_connector_name="mySecurityConnectorName")
package main
import (
security "github.com/pulumi/pulumi-azure-native-sdk/security/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := security.NewDevOpsConfiguration(ctx, "devOpsConfiguration", &security.DevOpsConfigurationArgs{
Properties: &security.DevOpsConfigurationPropertiesArgs{
Authorization: &security.AuthorizationArgs{
Code: pulumi.String("00000000000000000000"),
},
AutoDiscovery: pulumi.String(security.AutoDiscoveryDisabled),
},
ResourceGroupName: pulumi.String("myRg"),
SecurityConnectorName: pulumi.String("mySecurityConnectorName"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var devOpsConfiguration = new AzureNative.Security.DevOpsConfiguration("devOpsConfiguration", new()
{
Properties = new AzureNative.Security.Inputs.DevOpsConfigurationPropertiesArgs
{
Authorization = new AzureNative.Security.Inputs.AuthorizationArgs
{
Code = "00000000000000000000",
},
AutoDiscovery = AzureNative.Security.AutoDiscovery.Disabled,
},
ResourceGroupName = "myRg",
SecurityConnectorName = "mySecurityConnectorName",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.security.DevOpsConfiguration;
import com.pulumi.azurenative.security.DevOpsConfigurationArgs;
import com.pulumi.azurenative.security.inputs.DevOpsConfigurationPropertiesArgs;
import com.pulumi.azurenative.security.inputs.AuthorizationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var devOpsConfiguration = new DevOpsConfiguration("devOpsConfiguration", DevOpsConfigurationArgs.builder()
.properties(DevOpsConfigurationPropertiesArgs.builder()
.authorization(AuthorizationArgs.builder()
.code("00000000000000000000")
.build())
.autoDiscovery("Disabled")
.build())
.resourceGroupName("myRg")
.securityConnectorName("mySecurityConnectorName")
.build());
}
}
resources:
devOpsConfiguration:
type: azure-native:security:DevOpsConfiguration
properties:
properties:
authorization:
code: '00000000000000000000'
autoDiscovery: Disabled
resourceGroupName: myRg
securityConnectorName: mySecurityConnectorName
Setting autoDiscovery to Disabled limits scanning to repositories that exist at onboarding time. New repositories created after configuration won’t be automatically enrolled. This gives you control over which codebases are scanned without ongoing automatic expansion.
Onboard specific organizations or projects explicitly
When teams need granular control, they can specify exactly which top-level organizations or projects to scan.
import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";
const devOpsConfiguration = new azure_native.security.DevOpsConfiguration("devOpsConfiguration", {
properties: {
authorization: {
code: "00000000000000000000",
},
autoDiscovery: azure_native.security.AutoDiscovery.Disabled,
topLevelInventoryList: [
"org1",
"org2",
],
},
resourceGroupName: "myRg",
securityConnectorName: "mySecurityConnectorName",
});
import pulumi
import pulumi_azure_native as azure_native
dev_ops_configuration = azure_native.security.DevOpsConfiguration("devOpsConfiguration",
properties={
"authorization": {
"code": "00000000000000000000",
},
"auto_discovery": azure_native.security.AutoDiscovery.DISABLED,
"top_level_inventory_list": [
"org1",
"org2",
],
},
resource_group_name="myRg",
security_connector_name="mySecurityConnectorName")
package main
import (
security "github.com/pulumi/pulumi-azure-native-sdk/security/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := security.NewDevOpsConfiguration(ctx, "devOpsConfiguration", &security.DevOpsConfigurationArgs{
Properties: &security.DevOpsConfigurationPropertiesArgs{
Authorization: &security.AuthorizationArgs{
Code: pulumi.String("00000000000000000000"),
},
AutoDiscovery: pulumi.String(security.AutoDiscoveryDisabled),
TopLevelInventoryList: pulumi.StringArray{
pulumi.String("org1"),
pulumi.String("org2"),
},
},
ResourceGroupName: pulumi.String("myRg"),
SecurityConnectorName: pulumi.String("mySecurityConnectorName"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;
return await Deployment.RunAsync(() =>
{
var devOpsConfiguration = new AzureNative.Security.DevOpsConfiguration("devOpsConfiguration", new()
{
Properties = new AzureNative.Security.Inputs.DevOpsConfigurationPropertiesArgs
{
Authorization = new AzureNative.Security.Inputs.AuthorizationArgs
{
Code = "00000000000000000000",
},
AutoDiscovery = AzureNative.Security.AutoDiscovery.Disabled,
TopLevelInventoryList = new[]
{
"org1",
"org2",
},
},
ResourceGroupName = "myRg",
SecurityConnectorName = "mySecurityConnectorName",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.security.DevOpsConfiguration;
import com.pulumi.azurenative.security.DevOpsConfigurationArgs;
import com.pulumi.azurenative.security.inputs.DevOpsConfigurationPropertiesArgs;
import com.pulumi.azurenative.security.inputs.AuthorizationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var devOpsConfiguration = new DevOpsConfiguration("devOpsConfiguration", DevOpsConfigurationArgs.builder()
.properties(DevOpsConfigurationPropertiesArgs.builder()
.authorization(AuthorizationArgs.builder()
.code("00000000000000000000")
.build())
.autoDiscovery("Disabled")
.topLevelInventoryList(
"org1",
"org2")
.build())
.resourceGroupName("myRg")
.securityConnectorName("mySecurityConnectorName")
.build());
}
}
resources:
devOpsConfiguration:
type: azure-native:security:DevOpsConfiguration
properties:
properties:
authorization:
code: '00000000000000000000'
autoDiscovery: Disabled
topLevelInventoryList:
- org1
- org2
resourceGroupName: myRg
securityConnectorName: mySecurityConnectorName
The topLevelInventoryList property accepts organization or project names from your DevOps platform. Combined with disabled auto-discovery, this configuration scans only the specified organizations (“org1”, “org2”) and their repositories. New organizations won’t be added automatically.
Beyond these examples
These snippets focus on specific DevOps configuration features: auto-discovery modes, authorization configuration, and selective organization onboarding. They’re intentionally minimal rather than full security integrations.
The examples require pre-existing infrastructure such as a Microsoft Defender for Cloud security connector and OAuth authorization from your DevOps platform (GitHub, Azure DevOps, GitLab). They focus on configuring the DevOps connection rather than provisioning the security connector itself.
To keep things focused, common DevOps security patterns are omitted, including:
- Security connector creation and configuration
- OAuth flow and authorization code generation
- Repository-level filtering within organizations
- Scanning policies and compliance settings
These omissions are intentional: the goal is to illustrate how each DevOps configuration option is wired, not provide drop-in security modules. See the DevOpsConfiguration resource reference for all available configuration options.
Let's configure Azure DevOps Security
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Onboarding
You have three onboarding options:
- Enabled - Automatically onboards all current and future organizations
- Disabled (no list) - Onboards only currently existing organizations
- Disabled (with list) - Onboards only organizations specified in
topLevelInventoryList
autoDiscovery to Disabled and provide a topLevelInventoryList with the organization names you want to onboard (e.g., [“org1”, “org2”]).Authorization & Setup
authorization.code property is required for all DevOps configurations. All examples include this property, though the schema doesn’t provide details on how to obtain it.Resource Management
resourceGroupName and securityConnectorName are immutable and cannot be modified after creation. Changing these requires replacing the resource.