Documentation Index
Fetch the complete documentation index at: https://mintlify.com/grafana/grafana/llms.txt
Use this file to discover all available pages before exploring further.
This guide provides comprehensive security recommendations for deploying and operating Grafana in production environments.
Overview
Security in Grafana involves multiple layers:
- Network security and TLS/SSL
- Authentication and authorization
- Session management
- Application security
- Data protection
- Monitoring and auditing
Network Security
Use HTTPS Everywhere
Always use HTTPS in production:
[server]
protocol = https
cert_file = /path/to/cert.pem
cert_key = /path/to/key.pem
min_tls_version = "TLS1.2"
[security]
cookie_secure = true
strict_transport_security = true
strict_transport_security_max_age_seconds = 31536000
Restrict Network Access
-
Bind to specific interfaces
[server]
http_addr = 127.0.0.1 # Only localhost
-
Use firewall rules
# Allow only specific IPs
iptables -A INPUT -p tcp --dport 3000 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 3000 -j DROP
-
Deploy behind reverse proxy
- Use nginx, Apache, or cloud load balancers
- Terminate TLS at the proxy
- Add security headers
Domain and Origin Validation
[server]
enforce_domain = true
domain = grafana.example.com
root_url = https://grafana.example.com/
[security]
csrf_trusted_origins = grafana.example.com
Reference: conf/defaults.ini:53-60
Authentication Security
Disable Default Admin
Change default admin credentials immediately:
[security]
# Disable auto-creation of admin user
disable_initial_admin_creation = true
# Or change default credentials
admin_user = your_admin
admin_password = strong_random_password
Reference: conf/defaults.ini:374-384
Enforce Strong Passwords
[auth.basic]
enabled = true
# Require strong passwords (12+ chars, mixed case, numbers, symbols)
password_policy = true
Reference: conf/defaults.ini:950-959
Disable Anonymous Access
[auth.anonymous]
enabled = false
Use External Authentication
Prefer external authentication over basic auth:
- OAuth 2.0 with your identity provider
- LDAP/Active Directory integration
- SAML single sign-on
- JWT authentication
Enable Login Protection
[security]
# Brute force protection
disable_brute_force_login_protection = false
brute_force_login_protection_max_attempts = 5
# Per-IP rate limiting
disable_ip_address_login_protection = false
Reference: conf/defaults.ini:402-411
OAuth Security
When using OAuth:
[auth.generic_oauth]
# Use PKCE for public clients
use_pkce = true
# Validate ID tokens
validate_id_token = true
jwk_set_url = https://provider.com/.well-known/jwks.json
# Use refresh tokens
use_refresh_token = true
# Restrict domains
allowed_domains = company.com
# Verify TLS certificates
tls_skip_verify_insecure = false
tls_client_ca = /path/to/ca.crt
LDAP Security
Secure LDAP configuration:
[[servers]]
# Use TLS
use_ssl = true
start_tls = false
ssl_skip_verify = false
min_tls_version = "TLS1.2"
# Verify certificates
root_ca_cert = "/path/to/ca.crt"
# Use service account with minimal permissions
bind_dn = "cn=grafana,ou=services,dc=example,dc=com"
bind_password = "${LDAP_BIND_PASSWORD}"
Reference: pkg/services/ldap/settings.go:35-66
Authorization and Access Control
Principle of Least Privilege
Grant minimum necessary permissions:
-
Use built-in roles appropriately
- Viewer: Read-only access
- Editor: Create/edit dashboards
- Admin: Organization management
-
Limit Grafana Admin role
- Only for platform administrators
- Avoid granting via OAuth/SAML
[auth.generic_oauth]
allow_assign_grafana_admin = false
-
Use teams for group permissions
// Assign permissions to teams, not individuals
service.SetTeamPermission(ctx, orgID, teamID, resourceID, "View")
Restrict Sensitive Permissions
Limit access to:
- User management (
users:write, users:delete)
- Organization settings (
orgs:write)
- Datasource configuration (
datasources:write)
- Plugin installation (
plugins:write)
- LDAP configuration (
ldap.config:reload)
Reference: pkg/services/accesscontrol/models.go:347-532
Disable Self-Registration
[users]
allow_sign_up = false
allow_org_create = false
[auth.generic_oauth]
allow_sign_up = false
Organization Isolation
Use organizations to separate tenants:
[users]
# Users can only see their orgs
viewers_can_edit = false
editors_can_admin = false
[auth]
# Prevent automatic org assignment
auto_assign_org = false
Session Security
Session Configuration
[security]
# Secure cookies
cookie_secure = true
cookie_samesite = strict
# Sign cookies
secret_key = CHANGE_THIS_TO_RANDOM_STRING
Reference: conf/defaults.ini:387-417
Token Security
The authentication system manages tokens securely:
type UserTokenService interface {
// Create token with user context
CreateToken(ctx context.Context, cmd *CreateTokenCommand) (*UserToken, error)
// Rotate tokens on use
RotateToken(ctx context.Context, cmd RotateCommand) (*UserToken, error)
// Revoke compromised tokens
RevokeToken(ctx context.Context, token *UserToken, soft bool) error
// Limit concurrent sessions
ActiveTokenCount(ctx context.Context, userID *int64) (int64, error)
}
Reference: pkg/services/auth/auth.go:80-95
Session Limits
Limit concurrent sessions per user:
[quota]
enabled = true
global_session = 1000
# Per-organization session limits
org_session = 100
Reference: conf/defaults.ini:1296
Application Security
Enable all security headers:
[security]
# Content sniffing protection
x_content_type_options = true
# XSS protection
x_xss_protection = true
# Content Security Policy
content_security_policy = true
# Prevent embedding (unless needed)
allow_embedding = false
Reference: conf/defaults.ini:435-446
Content Security Policy
Configure strict CSP:
[security]
content_security_policy = true
content_security_policy_template = """script-src 'self' 'strict-dynamic' $NONCE;object-src 'none';base-uri 'self';connect-src 'self' wss://$ROOT_PATH;form-action 'self';"""
Reference: conf/defaults.ini:448-451
CSRF Protection
Enable CSRF protection:
[security]
# Check CSRF even without login cookie
csrf_always_check = true
# Trust specific origins
csrf_trusted_origins = grafana.example.com
# Additional validation headers
csrf_additional_headers = X-Forwarded-Host
The CSRF middleware validates requests:
func (c *CSRF) check(r *http.Request) error {
// Skip safe methods (HEAD, OPTIONS, TRACE)
// Validate Origin header matches request host
// Check against trusted origins
// Verify custom headers if configured
}
Reference: pkg/middleware/csrf/csrf.go:71-141
Grafana validates inputs to prevent:
- SQL injection
- Cross-site scripting (XSS)
- Command injection
- Path traversal
Action URL Validation
Restrict POST URLs in panel actions:
[security]
# Comma-separated list of allowed POST URLs
actions_allow_post_url = https://api.example.com/webhook
Reference: conf/defaults.ini:469
Implementation: pkg/middleware/validate_action_url.go
Data Protection
Secret Management
Use environment variables for secrets:
[database]
password = $__env{DB_PASSWORD}
[auth.generic_oauth]
client_secret = $__env{OAUTH_CLIENT_SECRET}
[smtp]
password = $__env{SMTP_PASSWORD}
Encryption at Rest
Grafana encrypts sensitive data:
[security]
# Encryption key (change this!)
secret_key = CHANGE_TO_RANDOM_STRING
# Current encryption provider
encryption_provider = secretKey.v1
# Additional providers (Enterprise)
available_encryption_providers = awskms.v1 azurekv.v1
Reference: conf/defaults.ini:387-393
Encrypted data includes:
- Datasource passwords
- OAuth tokens
- Alert notification credentials
- Plugin secrets
Encryption Key Management
[security.encryption]
# Cache TTL for decrypted keys
data_keys_cache_ttl = 15m
# Cache cleanup interval
data_keys_cache_cleanup_interval = 1m
Reference: conf/defaults.ini:472-478
Database Security
Secure database connections:
[database]
type = postgres
ssl_mode = verify-full
ca_cert_path = /path/to/ca.crt
client_cert_path = /path/to/client.crt
client_key_path = /path/to/client.key
Datasource Security
- Use proxy mode for datasources when possible
- Restrict datasource permissions
// Only allow necessary users to edit datasources
permission := Permission{
Action: "datasources:write",
Scope: "datasources:uid:abc123",
}
- Don’t store plaintext credentials in datasource configuration
- Use readonly database users for query datasources
Data Source Proxy Security
[dataproxy]
# Log proxy requests
logging = true
# Timeout settings
timeout = 30
dialTimeout = 10
# Limit response size
response_limit = 10485760 # 10MB
# Don't send user header
send_user_header = false
Reference: conf/defaults.ini:248-293
Plugin Security
Disable Unsigned Plugins
[plugins]
allow_loading_unsigned_plugins = false
Restrict Plugin Installation
Limit who can install plugins:
// Require specific permission
ac.Middleware(accessControl)(
ac.EvalPermission("plugins:write"),
)
Reference: pkg/middleware/auth.go:127-139
Plugin Sandboxing
[security]
# Sandbox specific plugins in frontend
enable_frontend_sandbox_for_plugins = plugin1,plugin2
Reference: conf/defaults.ini:466
Review Plugin Permissions
Before installing plugins:
- Check plugin signature
- Review source code (if possible)
- Verify plugin permissions
- Test in non-production environment
External Communication
Datasource Whitelist
[security]
# Whitelist datasource proxy destinations
data_source_proxy_whitelist = internal-network.com:443 metrics.company.com:9090
Reference: conf/defaults.ini:399
External Image Rendering
Secure image renderer:
[rendering]
# Use authenticated callback URL
server_url = https://grafana.example.com/
# Use separate renderer service
mode = remote
renderer_url = http://renderer:8081/render
Alerting Security
- Validate notification URLs
- Use secure webhooks (HTTPS only)
- Authenticate alert notifications
- Rate limit alerts
Deployment Security
Run as Non-Root User
# Create dedicated user
useradd -r -s /bin/false grafana
# Set ownership
chown -R grafana:grafana /var/lib/grafana
chown -R grafana:grafana /etc/grafana
# Run as grafana user
su - grafana -c "grafana-server"
File Permissions
# Restrict configuration files
chmod 640 /etc/grafana/grafana.ini
chown root:grafana /etc/grafana/grafana.ini
# Restrict data directory
chmod 750 /var/lib/grafana
chown grafana:grafana /var/lib/grafana
# Restrict certificate files
chmod 600 /etc/grafana/cert.key
chown grafana:grafana /etc/grafana/cert.key
Container Security
# Use official image
FROM grafana/grafana:latest
# Run as non-root
USER grafana
# Read-only root filesystem
# docker run --read-only -v /var/lib/grafana:/var/lib/grafana
# Drop capabilities
# docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE
# Resource limits
# docker run --memory=1g --cpus=1
Kubernetes Security
apiVersion: v1
kind: Pod
metadata:
name: grafana
spec:
securityContext:
runAsNonRoot: true
runAsUser: 472
fsGroup: 472
seccompProfile:
type: RuntimeDefault
containers:
- name: grafana
image: grafana/grafana:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: storage
mountPath: /var/lib/grafana
resources:
limits:
memory: "1Gi"
cpu: "1"
requests:
memory: "512Mi"
cpu: "500m"
Monitoring and Auditing
Enable Audit Logging
[log]
# Set appropriate log level
level = info
# Log to files
mode = console file
[log.file]
log_rotate = true
max_days = 7
Reference: conf/defaults.ini:1161-1203
Monitor Authentication
Track authentication events:
- Failed login attempts
- Password changes
- Role changes
- Permission modifications
Enable Metrics
Monitor security metrics:
[metrics]
enabled = true
[analytics]
reporting_enabled = true
Security Scanning
-
Vulnerability scanning
# Scan Docker image
docker scan grafana/grafana:latest
# Scan with Trivy
trivy image grafana/grafana:latest
-
Dependency scanning
- Monitor for CVEs in dependencies
- Keep Grafana updated
- Apply security patches promptly
Incident Response
Token Revocation
Revoke compromised tokens:
# Via API
curl -X POST https://grafana.example.com/api/user/revoke-auth-token \
-H "Authorization: Bearer $TOKEN"
# Revoke all user tokens
curl -X POST https://grafana.example.com/api/admin/users/:id/revoke-auth-token \
-H "Authorization: Bearer $ADMIN_TOKEN"
Implementation: pkg/services/auth/auth.go:90-91
Password Reset
# Reset user password (CLI)
grafana-cli admin reset-admin-password newpassword
# Force password change via API
curl -X PUT https://grafana.example.com/api/admin/users/:id/password \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-d '{"password":"newpassword"}'
Security Breach Response
- Isolate affected systems
- Revoke all active sessions
err := tokenService.RevokeAllUserTokens(ctx, userID)
- Rotate encryption keys
- Review access logs
- Update credentials
- Apply patches
- Notify stakeholders
Compliance
GDPR Compliance
- Implement data retention policies
- Enable user data export
- Provide data deletion capabilities
- Log data access
SOC 2 Compliance
- Enable audit logging
- Implement access controls
- Use encryption in transit and at rest
- Regular security reviews
HIPAA Compliance
- Encrypt all data
- Implement access controls
- Enable comprehensive audit logging
- Regular risk assessments
Regular Maintenance
Security Checklist
Update Process
- Test updates in non-production environment
- Review changelog for security fixes
- Backup configuration and data
- Apply update during maintenance window
- Verify functionality
- Monitor for issues
Security Resources
Grafana Security
Security Standards