GrafanaOidcIntegration.java
package com.cloudforge.core.oidc;
import com.cloudforge.core.interfaces.Ec2Context;
import com.cloudforge.core.interfaces.OidcConfiguration;
import com.cloudforge.core.interfaces.OidcIntegration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* OIDC integration for Grafana using generic_oauth provider.
*
* <p>Grafana has excellent built-in OIDC support via the generic_oauth provider.
* Configuration is done entirely through environment variables.</p>
*
* <p><strong>Supported OIDC Providers:</strong></p>
* <ul>
* <li>Amazon Cognito</li>
* <li>IAM Identity Center</li>
* <li>Any OIDC-compliant provider</li>
* </ul>
*
* <p><strong>Features:</strong></p>
* <ul>
* <li>Auto-create users on first login</li>
* <li>Group/role mapping from OIDC claims</li>
* <li>Admin role assignment via group membership</li>
* <li>PKCE support</li>
* </ul>
*
* @see <a href="https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-authentication/generic-oauth/">Grafana OAuth Documentation</a>
*/
public class GrafanaOidcIntegration implements OidcIntegration {
@Override
public boolean isSupported() {
return true;
}
@Override
public String getIntegrationMethod() {
return "Built-in generic_oauth provider (configured via environment variables)";
}
@Override
public Map<String, String> getEnvironmentVariables(OidcConfiguration config) {
Map<String, String> env = new HashMap<>();
// Configure Grafana root URL if available (required for OAuth redirects, dashboards, alerts)
String rootUrl = config.getApplicationUrl();
if (rootUrl != null && !rootUrl.isEmpty()) {
env.put("GF_SERVER_ROOT_URL", rootUrl);
}
// Enable generic OAuth
env.put("GF_AUTH_GENERIC_OAUTH_ENABLED", "true");
// Provider name (shown on login page)
String providerName = config.getProviderType().equals("cognito") ?
"AWS Cognito" : "AWS IAM Identity Center";
env.put("GF_AUTH_GENERIC_OAUTH_NAME", providerName);
// OAuth endpoints
env.put("GF_AUTH_GENERIC_OAUTH_CLIENT_ID", config.getClientId());
env.put("GF_AUTH_GENERIC_OAUTH_AUTH_URL", config.getAuthorizationEndpoint());
env.put("GF_AUTH_GENERIC_OAUTH_TOKEN_URL", config.getTokenEndpoint());
env.put("GF_AUTH_GENERIC_OAUTH_API_URL", config.getUserInfoEndpoint());
// Scopes
env.put("GF_AUTH_GENERIC_OAUTH_SCOPES", config.getScopes());
// User mapping
env.put("GF_AUTH_GENERIC_OAUTH_LOGIN_ATTRIBUTE_PATH", config.getUsernameClaim());
env.put("GF_AUTH_GENERIC_OAUTH_NAME_ATTRIBUTE_PATH", config.getFullNameClaim());
env.put("GF_AUTH_GENERIC_OAUTH_EMAIL_ATTRIBUTE_PATH", config.getEmailClaim());
// Groups/role mapping
env.put("GF_AUTH_GENERIC_OAUTH_GROUPS_ATTRIBUTE_PATH", config.getGroupsClaim());
env.put("GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH", "");
// Map OIDC groups to Grafana roles
// Users in admin group get Admin role, others get Editor role
// Note: Advanced role mapping requires Grafana Enterprise
env.put("GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_STRICT", "false");
// Auto-create users
env.put("GF_AUTH_GENERIC_OAUTH_AUTO_LOGIN", "false");
env.put("GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP", String.valueOf(config.isAutoCreateUsers()));
// Security
env.put("GF_AUTH_GENERIC_OAUTH_USE_PKCE", String.valueOf(config.usePkce()));
env.put("GF_AUTH_GENERIC_OAUTH_TLS_SKIP_VERIFY_INSECURE", "false");
// The client secret is retrieved from AWS Secrets Manager at runtime
// This is handled by the userdata script
env.put("GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET", "${GRAFANA_OAUTH_CLIENT_SECRET}");
return env;
}
@Override
public List<String> getUserDataCommands(OidcConfiguration config, Ec2Context context) {
List<String> commands = new ArrayList<>();
commands.add("# Configure Grafana OIDC integration");
commands.add("# Retrieve client secret from AWS Secrets Manager");
commands.add("export GRAFANA_OAUTH_CLIENT_SECRET=$(aws secretsmanager get-secret-value \\");
commands.add(" --secret-id " + config.getClientSecretArn() + " \\");
commands.add(" --region " + context.stackName().split("-")[0] + " \\"); // Extract region from stack name
commands.add(" --query SecretString --output text)");
commands.add("");
commands.add("# Set environment variables for Grafana OAuth");
commands.add("cat >> /etc/grafana/grafana-env.sh <<'EOF'");
// Configure Grafana root URL if available (required for OAuth redirects, dashboards, alerts)
String rootUrl = config.getApplicationUrl();
if (rootUrl != null && !rootUrl.isEmpty()) {
commands.add("export GF_SERVER_ROOT_URL=\"" + rootUrl + "\"");
}
commands.add("export GF_AUTH_GENERIC_OAUTH_ENABLED=true");
commands.add("export GF_AUTH_GENERIC_OAUTH_NAME=\"" + (config.getProviderType().equals("cognito") ? "AWS Cognito" : "AWS IAM Identity Center") + "\"");
commands.add("export GF_AUTH_GENERIC_OAUTH_CLIENT_ID=\"" + config.getClientId() + "\"");
commands.add("export GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET=\"$GRAFANA_OAUTH_CLIENT_SECRET\"");
commands.add("export GF_AUTH_GENERIC_OAUTH_AUTH_URL=\"" + config.getAuthorizationEndpoint() + "\"");
commands.add("export GF_AUTH_GENERIC_OAUTH_TOKEN_URL=\"" + config.getTokenEndpoint() + "\"");
commands.add("export GF_AUTH_GENERIC_OAUTH_API_URL=\"" + config.getUserInfoEndpoint() + "\"");
commands.add("export GF_AUTH_GENERIC_OAUTH_SCOPES=\"" + config.getScopes() + "\"");
commands.add("export GF_AUTH_GENERIC_OAUTH_LOGIN_ATTRIBUTE_PATH=\"" + config.getUsernameClaim() + "\"");
commands.add("export GF_AUTH_GENERIC_OAUTH_EMAIL_ATTRIBUTE_PATH=\"" + config.getEmailClaim() + "\"");
commands.add("export GF_AUTH_GENERIC_OAUTH_GROUPS_ATTRIBUTE_PATH=\"" + config.getGroupsClaim() + "\"");
commands.add("export GF_AUTH_GENERIC_OAUTH_USE_PKCE=" + config.usePkce());
commands.add("export GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP=" + config.isAutoCreateUsers());
commands.add("EOF");
commands.add("");
commands.add("# Source environment variables in Grafana systemd service");
commands.add("echo 'EnvironmentFile=/etc/grafana/grafana-env.sh' >> /usr/lib/systemd/system/grafana-server.service");
commands.add("systemctl daemon-reload");
commands.add("systemctl restart grafana-server");
commands.add("echo 'Grafana OIDC integration configured' >> /var/log/userdata.log");
return commands;
}
@Override
public String getContainerStartupCommand() {
return "/run.sh";
}
@Override
public boolean supportsCognito() {
// Full support - Grafana generic_oauth works with Cognito OIDC
return true;
}
@Override
public boolean supportsIdentityCenterSaml() {
// Grafana supports SAML but this integration uses OIDC
// For SAML, create a GrafanaSamlIntegration class
return false;
}
@Override
public String getAuthenticationType() {
return "OIDC";
}
@Override
public String getPostDeploymentInstructions() {
return """
Grafana OIDC Integration Completed
===================================
1. Access Grafana at: https://{your-domain}:3000
2. Click "Sign in with %s" on the login page
3. You will be redirected to the OIDC provider
4. After authentication, you'll be logged into Grafana
Role Mapping:
- Users in '%s' group: Grafana Admin role
- Other authenticated users: Grafana Editor role
To manage users and permissions:
- Use the OIDC provider (Cognito/Identity Center)
- Grafana will auto-create users on first login
- Role assignment is based on group membership
""";
}
}