> ## 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.

# Security Best Practices

> Comprehensive security best practices for deploying and operating Grafana

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:

```ini theme={null}
[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

1. **Bind to specific interfaces**
   ```ini theme={null}
   [server]
   http_addr = 127.0.0.1  # Only localhost
   ```

2. **Use firewall rules**
   ```bash theme={null}
   # 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
   ```

3. **Deploy behind reverse proxy**
   * Use nginx, Apache, or cloud load balancers
   * Terminate TLS at the proxy
   * Add security headers

### Domain and Origin Validation

```ini theme={null}
[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:

```ini theme={null}
[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

```ini theme={null}
[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

```ini theme={null}
[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

```ini theme={null}
[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:

```ini theme={null}
[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:

```toml theme={null}
[[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:

1. **Use built-in roles appropriately**
   * Viewer: Read-only access
   * Editor: Create/edit dashboards
   * Admin: Organization management

2. **Limit Grafana Admin role**
   * Only for platform administrators
   * Avoid granting via OAuth/SAML
   ```ini theme={null}
   [auth.generic_oauth]
   allow_assign_grafana_admin = false
   ```

3. **Use teams for group permissions**
   ```go theme={null}
   // 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

```ini theme={null}
[users]
allow_sign_up = false
allow_org_create = false

[auth.generic_oauth]
allow_sign_up = false
```

### Organization Isolation

Use organizations to separate tenants:

```ini theme={null}
[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

```ini theme={null}
[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:

```go theme={null}
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:

```ini theme={null}
[quota]
enabled = true
global_session = 1000

# Per-organization session limits
org_session = 100
```

Reference: `conf/defaults.ini:1296`

## Application Security

### Security Headers

Enable all security headers:

```ini theme={null}
[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:

```ini theme={null}
[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:

```ini theme={null}
[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:

```go theme={null}
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`

### Input Validation

Grafana validates inputs to prevent:

* SQL injection
* Cross-site scripting (XSS)
* Command injection
* Path traversal

### Action URL Validation

Restrict POST URLs in panel actions:

```ini theme={null}
[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:

```ini theme={null}
[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:

```ini theme={null}
[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

```ini theme={null}
[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:

```ini theme={null}
[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

1. **Use proxy mode** for datasources when possible
2. **Restrict datasource permissions**
   ```go theme={null}
   // Only allow necessary users to edit datasources
   permission := Permission{
       Action: "datasources:write",
       Scope:  "datasources:uid:abc123",
   }
   ```
3. **Don't store plaintext credentials** in datasource configuration
4. **Use readonly database users** for query datasources

### Data Source Proxy Security

```ini theme={null}
[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

```ini theme={null}
[plugins]
allow_loading_unsigned_plugins = false
```

### Restrict Plugin Installation

Limit who can install plugins:

```go theme={null}
// Require specific permission
ac.Middleware(accessControl)(
    ac.EvalPermission("plugins:write"),
)
```

Reference: `pkg/middleware/auth.go:127-139`

### Plugin Sandboxing

```ini theme={null}
[security]
# Sandbox specific plugins in frontend
enable_frontend_sandbox_for_plugins = plugin1,plugin2
```

Reference: `conf/defaults.ini:466`

### Review Plugin Permissions

Before installing plugins:

1. Check plugin signature
2. Review source code (if possible)
3. Verify plugin permissions
4. Test in non-production environment

## External Communication

### Datasource Whitelist

```ini theme={null}
[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:

```ini theme={null}
[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

1. **Validate notification URLs**
2. **Use secure webhooks** (HTTPS only)
3. **Authenticate alert notifications**
4. **Rate limit alerts**

## Deployment Security

### Run as Non-Root User

```bash theme={null}
# 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

```bash theme={null}
# 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

```dockerfile theme={null}
# 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

```yaml theme={null}
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

```ini theme={null}
[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:

```ini theme={null}
[metrics]
enabled = true

[analytics]
reporting_enabled = true
```

### Security Scanning

1. **Vulnerability scanning**
   ```bash theme={null}
   # Scan Docker image
   docker scan grafana/grafana:latest

   # Scan with Trivy
   trivy image grafana/grafana:latest
   ```

2. **Dependency scanning**
   * Monitor for CVEs in dependencies
   * Keep Grafana updated
   * Apply security patches promptly

## Incident Response

### Token Revocation

Revoke compromised tokens:

```bash theme={null}
# 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

```bash theme={null}
# 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

1. **Isolate affected systems**
2. **Revoke all active sessions**
   ```go theme={null}
   err := tokenService.RevokeAllUserTokens(ctx, userID)
   ```
3. **Rotate encryption keys**
4. **Review access logs**
5. **Update credentials**
6. **Apply patches**
7. **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

* [ ] Keep Grafana updated
* [ ] Review and rotate credentials quarterly
* [ ] Audit user permissions monthly
* [ ] Review access logs weekly
* [ ] Test backup restoration monthly
* [ ] Update TLS certificates before expiration
* [ ] Review and update security policies annually
* [ ] Conduct security training for users
* [ ] Test incident response procedures
* [ ] Scan for vulnerabilities regularly

### Update Process

1. **Test updates** in non-production environment
2. **Review changelog** for security fixes
3. **Backup configuration and data**
4. **Apply update** during maintenance window
5. **Verify functionality**
6. **Monitor for issues**

## Security Resources

### Grafana Security

* Security advisories: [https://grafana.com/security](https://grafana.com/security)
* Security policy: [https://github.com/grafana/grafana/security/policy](https://github.com/grafana/grafana/security/policy)
* Report vulnerabilities: [security@grafana.com](mailto:security@grafana.com)

### Security Standards

* OWASP Top 10: [https://owasp.org/Top10/](https://owasp.org/Top10/)
* CIS Benchmarks: [https://www.cisecurity.org/](https://www.cisecurity.org/)
* NIST Guidelines: [https://www.nist.gov/cyberframework](https://www.nist.gov/cyberframework)

## Related Topics

* [Authentication](/deployment/security/authentication) - Configure authentication methods
* [Authorization](/deployment/security/authorization) - Role-based access control
* [TLS/SSL Configuration](/deployment/security/tls-ssl) - Secure communication
* [High Availability](/deployment/high-availability) - Resilient deployments
