@kotaicode/pulumi-dex
v0.8.0
Published
A Pulumi provider for managing Dex (https://dexidp.io/) resources via the Dex gRPC Admin API. This provider allows you to manage Dex OAuth2 clients and connectors (IdPs) as infrastructure-as-code.
Keywords
Readme
Pulumi Provider for Dex
A Pulumi provider for managing Dex (https://dexidp.io/) resources via the Dex gRPC Admin API. This provider allows you to manage Dex OAuth2 clients and connectors (IdPs) as infrastructure-as-code.
Features
- OAuth2 Client Management: Create, update, and delete Dex OAuth2 clients
- Generic Connector Support: Manage any Dex connector type (OIDC, LDAP, SAML, etc.)
- OIDC Connector Support: First-class support for OIDC connectors with typed configuration
- Azure/Entra ID Integration:
AzureOidcConnector- Uses generic OIDC connector (type:oidc)AzureMicrosoftConnector- Uses Dex's Microsoft-specific connector (type:microsoft)
- AWS Cognito Integration:
CognitoOidcConnectorfor managing Cognito user pools as IdPs - GitLab Integration:
GitLabConnectorfor GitLab.com and self-hosted GitLab instances - GitHub Integration:
GitHubConnectorfor GitHub.com and GitHub Enterprise - Google Integration:
GoogleConnectorfor Google Workspace and Google accounts - Local/Builtin Connector:
LocalConnectorfor local user authentication
Installation
Prerequisites
- Pulumi CLI installed
- Go 1.24+ (for building the provider)
- Access to a Dex instance with gRPC API enabled
Building the Provider
# Clone the repository
git clone https://github.com/kotaicode/pulumi-dex.git
cd pulumi-dex
# Build the provider binary
go build -o bin/pulumi-resource-dex ./cmd/pulumi-resource-dex
# Install the provider locally
pulumi plugin install resource dex v0.1.0 --file bin/pulumi-resource-dexGenerating Language SDKs
After building the provider, generate SDKs for your preferred language:
# Generate TypeScript SDK
pulumi package gen-sdk bin/pulumi-resource-dex --language typescript --out sdk/typescript
# Generate Go SDK
pulumi package gen-sdk bin/pulumi-resource-dex --language go --out sdk/go
# Generate Python SDK (optional)
pulumi package gen-sdk bin/pulumi-resource-dex --language python --out sdk/pythonConfiguration
The provider requires configuration to connect to your Dex gRPC API:
import * as dex from "@kotaicode/pulumi-dex";
const provider = new dex.Provider("dex", {
host: "dex.internal:5557", // Dex gRPC host:port
// Optional: TLS configuration for mTLS
caCert: fs.readFileSync("certs/ca.crt", "utf-8"),
clientCert: fs.readFileSync("certs/client.crt", "utf-8"),
clientKey: fs.readFileSync("certs/client.key", "utf-8"),
// Or for development:
// insecureSkipVerify: true,
});Environment Variables
You can also configure the provider using environment variables:
DEX_HOST- Dex gRPC host:portDEX_CA_CERT- PEM-encoded CA certificateDEX_CLIENT_CERT- PEM-encoded client certificateDEX_CLIENT_KEY- PEM-encoded client private keyDEX_INSECURE_SKIP_VERIFY- Skip TLS verification (development only)DEX_TIMEOUT_SECONDS- Per-RPC timeout in seconds
Usage Examples
Managing an OAuth2 Client
import * as dex from "@kotaicode/pulumi-dex";
const webClient = new dex.Client("webClient", {
clientId: "my-web-app",
name: "My Web App",
redirectUris: ["https://app.example.com/callback"],
// secret is optional - will be auto-generated if omitted
}, { provider });
export const clientSecret = webClient.secret; // Pulumi secretAzure/Entra ID Connector (Generic OIDC)
const azureConnector = new dex.AzureOidcConnector("azure-tenant-a", {
connectorId: "azure-tenant-a",
name: "Azure AD (Tenant A)",
tenantId: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
clientId: "your-azure-app-client-id",
clientSecret: "your-azure-app-client-secret", // Pulumi secret
redirectUri: "https://dex.example.com/callback",
scopes: ["openid", "profile", "email", "offline_access"],
userNameSource: "preferred_username", // or "upn" or "email"
}, { provider });Azure/Entra ID Connector (Microsoft-Specific)
const azureMsConnector = new dex.AzureMicrosoftConnector("azure-ms", {
connectorId: "azure-ms",
name: "Azure AD (Microsoft Connector)",
tenant: "common", // or "organizations" or specific tenant ID
clientId: "your-azure-app-client-id",
clientSecret: "your-azure-app-client-secret",
redirectUri: "https://dex.example.com/callback",
groups: "groups", // Optional: group claim name
}, { provider });AWS Cognito Connector
const cognitoConnector = new dex.CognitoOidcConnector("cognito-eu", {
connectorId: "cognito-eu",
name: "Cognito (EU)",
region: "eu-central-1",
userPoolId: "eu-central-1_XXXXXXX",
clientId: "your-cognito-app-client-id",
clientSecret: "your-cognito-app-client-secret",
redirectUri: "https://dex.example.com/callback",
userNameSource: "email", // or "sub"
}, { provider });GitLab Connector
const gitlabConnector = new dex.GitLabConnector("gitlab", {
connectorId: "gitlab",
name: "GitLab",
clientId: "your-gitlab-client-id",
clientSecret: "your-gitlab-client-secret",
redirectUri: "https://dex.example.com/callback",
baseURL: "https://gitlab.com", // Optional, defaults to https://gitlab.com
groups: ["my-group"], // Optional: groups whitelist
useLoginAsID: false, // Optional: use username as ID instead of internal ID
getGroupsPermission: false, // Optional: include group permissions in groups claim
}, { provider });GitHub Connector
const githubConnector = new dex.GitHubConnector("github", {
connectorId: "github",
name: "GitHub",
clientId: "your-github-client-id",
clientSecret: "your-github-client-secret",
redirectUri: "https://dex.example.com/callback",
orgs: [
{ name: "my-organization" },
{
name: "my-organization-with-teams",
teams: ["red-team", "blue-team"]
}
],
teamNameField: "slug", // Optional: "name", "slug", or "both" - default: "slug"
useLoginAsID: false, // Optional: use username as ID
// For GitHub Enterprise:
// hostName: "git.example.com",
// rootCA: "/etc/dex/ca.crt",
}, { provider });Google Connector
const googleConnector = new dex.GoogleConnector("google", {
connectorId: "google",
name: "Google",
clientId: "your-google-client-id",
clientSecret: "your-google-client-secret",
redirectUri: "https://dex.example.com/callback",
promptType: "consent", // Optional: default is "consent"
hostedDomains: ["example.com"], // Optional: domain whitelist for G Suite
groups: ["[email protected]"], // Optional: group whitelist for G Suite
// For group fetching:
// serviceAccountFilePath: "/path/to/googleAuth.json",
// domainToAdminEmail: {
// "*": "[email protected]",
// "my-domain.com": "[email protected]"
// },
}, { provider });Local/Builtin Connector
const localConnector = new dex.LocalConnector("local", {
connectorId: "local",
name: "Local",
enabled: true, // Optional: default is true
}, { provider });Generic Connector (OIDC)
const genericOidcConnector = new dex.Connector("github-oidc", {
connectorId: "github-oidc",
type: "oidc",
name: "GitHub OIDC",
oidcConfig: {
issuer: "https://token.actions.githubusercontent.com",
clientId: "your-github-oidc-client-id",
clientSecret: "your-secret",
redirectUri: "https://dex.example.com/callback",
scopes: ["openid", "email", "profile"],
},
}, { provider });Generic Connector (Raw JSON)
const githubConnector = new dex.Connector("github", {
connectorId: "github",
type: "github",
name: "GitHub",
rawConfig: JSON.stringify({
clientID: "your-github-client-id",
clientSecret: "your-github-client-secret",
redirectURI: "https://dex.example.com/callback",
orgs: ["kotaicode"],
}),
}, { provider });Resources
dex.Client
Manages an OAuth2 client in Dex.
Inputs:
clientId(string, required) - Unique identifier for the clientname(string, required) - Display namesecret(string, optional, secret) - Client secret (auto-generated if omitted)redirectUris(string[], required) - Allowed redirect URIstrustedPeers(string[], optional) - Trusted peer client IDspublic(boolean, optional) - Public (non-confidential) clientlogoUrl(string, optional) - Logo image URL
Outputs:
id- Resource ID (same as clientId)clientId- The client IDsecret- The client secret (Pulumi secret)createdAt- Creation timestamp
dex.Connector
Manages a generic connector in Dex.
Inputs:
connectorId(string, required) - Unique identifiertype(string, required) - Connector type (e.g., "oidc", "ldap", "saml", "github")name(string, required) - Display nameoidcConfig(OIDCConfig, optional) - OIDC configuration (use when type="oidc")rawConfig(string, optional) - Raw JSON configuration (for non-OIDC connectors)
Note: Exactly one of oidcConfig or rawConfig must be provided.
dex.AzureOidcConnector
Manages an Azure AD/Entra ID connector using generic OIDC.
Inputs:
connectorId(string, required)name(string, required)tenantId(string, required) - Azure tenant ID (UUID)clientId(string, required) - Azure app client IDclientSecret(string, required, secret) - Azure app client secretredirectUri(string, required)scopes(string[], optional) - Defaults to["openid", "profile", "email", "offline_access"]userNameSource(string, optional) - "preferred_username" (default), "upn", or "email"extraOidc(map, optional) - Additional OIDC config fields
dex.AzureMicrosoftConnector
Manages an Azure AD/Entra ID connector using Dex's Microsoft-specific connector.
Inputs:
connectorId(string, required)name(string, required)tenant(string, required) - "common", "organizations", or tenant ID (UUID)clientId(string, required)clientSecret(string, required, secret)redirectUri(string, required)groups(string, optional) - Group claim name (requires admin consent)
dex.CognitoOidcConnector
Manages an AWS Cognito user pool connector.
Inputs:
connectorId(string, required)name(string, required)region(string, required) - AWS region (e.g., "eu-central-1")userPoolId(string, required) - Cognito user pool IDclientId(string, required) - Cognito app client IDclientSecret(string, required, secret) - Cognito app client secretredirectUri(string, required)scopes(string[], optional) - Defaults to["openid", "email", "profile"]userNameSource(string, optional) - "email" (default) or "sub"extraOidc(map, optional) - Additional OIDC config fields
dex.GitLabConnector
Manages a GitLab connector in Dex.
Inputs:
connectorId(string, required)name(string, required)clientId(string, required) - GitLab application client IDclientSecret(string, required, secret) - GitLab application client secretredirectUri(string, required)baseURL(string, optional) - GitLab instance URL, defaults tohttps://gitlab.comgroups(string[], optional) - Groups whitelistuseLoginAsID(bool, optional) - Use username as ID instead of internal ID, default:falsegetGroupsPermission(bool, optional) - Include group permissions in groups claim, default:false
dex.GitHubConnector
Manages a GitHub connector in Dex.
Inputs:
connectorId(string, required)name(string, required)clientId(string, required) - GitHub OAuth app client IDclientSecret(string, required, secret) - GitHub OAuth app client secretredirectUri(string, required)orgs(GitHubOrg[], optional) - List of organizations and teamsname(string, required) - Organization nameteams(string[], optional) - Team names within the organization
loadAllGroups(bool, optional) - Load all user orgs/teams, default:falseteamNameField(string, optional) - "name", "slug", or "both", default: "slug"useLoginAsID(bool, optional) - Use username as ID, default:falsepreferredEmailDomain(string, optional) - Preferred email domainhostName(string, optional) - GitHub Enterprise hostnamerootCA(string, optional) - Root CA certificate path for GitHub Enterprise
dex.GoogleConnector
Manages a Google connector in Dex.
Inputs:
connectorId(string, required)name(string, required)clientId(string, required) - Google OAuth client IDclientSecret(string, required, secret) - Google OAuth client secretredirectUri(string, required)promptType(string, optional) - OIDC prompt parameter, default: "consent"hostedDomains(string[], optional) - Domain whitelist for G Suitegroups(string[], optional) - Group whitelist for G SuiteserviceAccountFilePath(string, optional) - Service account JSON file path for group fetchingdomainToAdminEmail(map[string]string, optional) - Domain to admin email mapping for group fetching
dex.LocalConnector
Manages a local/builtin connector in Dex.
Inputs:
connectorId(string, required)name(string, required)enabled(bool, optional) - Whether the connector is enabled, default:true
Note: The local connector requires enablePasswordDB: true in Dex configuration. User management is handled separately via Dex's static passwords or gRPC API.
Local Development and Testing
Running Dex Locally with Docker Compose
See docker-compose.yml for a local Dex setup with gRPC API enabled.
# Start Dex
docker-compose up -d
# Dex gRPC will be available at localhost:5557
# Dex web UI will be available at http://localhost:5556Example Pulumi Program
See the examples/ directory for complete example programs.
Dex Configuration Requirements
Your Dex instance must have the gRPC API enabled. Add this to your Dex configuration:
grpc:
addr: 127.0.0.1:5557
tlsCert: /etc/dex/grpc.crt
tlsKey: /etc/dex/grpc.key
tlsClientCA: /etc/dex/client.crt
reflection: true
# Enable connector CRUD (required for connector management)
enablePasswordDB: falseAnd set the environment variable:
export DEX_API_CONNECTORS_CRUD=trueSecurity Considerations
- Secrets: All secrets (client secrets, TLS keys) are automatically marked as Pulumi secrets and encrypted in state
- mTLS: Strongly recommended for production use. Configure TLS certificates properly
- Network: Ensure Dex gRPC API is only accessible from trusted networks
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
Dex Version Compatibility
This provider has been tested with:
- Dex v2.4.0+ (with
DEX_API_CONNECTORS_CRUD=true)
The provider requires:
- Dex gRPC API enabled
DEX_API_CONNECTORS_CRUD=trueenvironment variable set on Dex (required for connector CRUD operations)
For older Dex versions, connector management may not be available. Client management should work with any Dex version that exposes the gRPC API.
Development
Prerequisites
- Go 1.24.1+
- Pulumi CLI
- Docker and Docker Compose (for local testing)
Building
make buildRunning Tests
# Unit tests
make test
# Integration tests (requires Dex running)
make dex-up
make test # Run tests with integration tag
make dex-downCode Quality
# Run linter
golangci-lint run
# Format code
go fmt ./...Contributing
Contributions are welcome! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
License
[License TBD - Add MIT or Apache 2.0]
Support
- GitHub Issues: https://github.com/kotaicode/pulumi-dex/issues
- Documentation: https://github.com/kotaicode/pulumi-dex#readme
