Securing Grafana
1. Enabling HTTPS
| Configuration Option | Value | Description |
|---|---|---|
| server.protocol | https |
Sets the protocol to HTTPS for secure connections |
| server.http_port | 443 |
Default HTTPS port (can be changed) |
| server.cert_file | /path/to/cert.pem |
Path to the SSL certificate file |
| server.key_file | /path/to/key.pem |
Path to the SSL private key file |
Example: Grafana configuration for HTTPS
[server]
protocol = https
http_port = 443
cert_file = /etc/ssl/certs/grafana.pem
key_file = /etc/ssl/private/grafana.key
Note: Ensure the certificate and key files are readable by the Grafana process and have proper permissions (e.g., 600).
2. Configuring Security Headers
| Header | Value | Description |
|---|---|---|
| X-Content-Type-Options | nosniff |
Prevents the browser from interpreting files as a different MIME type than what is declared. |
| X-Frame-Options | DENY or SAMEORIGIN |
Prevents the page from being embedded in an iframe, protecting against clickjacking attacks. |
| X-XSS-Protection | 1; mode=block |
Enables the browser's built-in XSS filtering. |
| Strict-Transport-Security | max-age=31536000; includeSubDomains |
Enforces secure (HTTPS) connections for the domain and its subdomains. |
| Content-Security-Policy | default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' |
Defines which sources of content are allowed to be loaded by the browser. |
Example: Configuring Security Headers in Grafana
[security]
; Enable security headers
x_content_type_options = true
x_frame_options = DENY
x_xss_protection = true
strict_transport_security = true
content_security_policy = default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
3. Setting Cookie Security
| Option | Values | Notes |
|---|---|---|
| cookie.secure | true |
Ensures cookies are only sent over HTTPS |
| cookie.sameSite | lax |
Prevents CSRF attacks; options: strict, lax, none |
| cookie.httpOnly | true |
Prevents XSS attacks by making cookies inaccessible to JavaScript |
Example: Cookie Security Configuration
[security]
cookie.secure = true
cookie.sameSite = lax
cookie.httpOnly = true
Note: Setting
cookie.sameSite = none requires cookie.secure = true for browsers to accept the cookie.
4. Enabling CSRF Protection
CSRF (Cross-Site Request Forgery) protection in Grafana helps prevent unauthorized commands from being executed on behalf of authenticated users. It ensures that requests originate from trusted sources within the Grafana application.
| Configuration Option | Description | Default Value | Notes |
|---|---|---|---|
| csrf.protection.enabled | Enables or disables CSRF protection | false |
Set to true to enable CSRF protection |
| csrf.protection.token.header | Header name used to pass the CSRF token | X-CSRF-Token |
Can be customized for specific environments |
Example: Enabling CSRF Protection in grafana.ini
[security]
csrf.protection.enabled = true
csrf.protection.token.header = X-CSRF-Token
Note: Enabling CSRF protection may require updating frontend applications or API clients to include the CSRF token in requests.
5. Configuring CORS Settings
Example: Grafana CORS Configuration
[cors]
enabled = true
allow_origins = https://grafana.example.com,https://dashboard.example.org
allow_headers = Authorization,Content-Type
allow_methods = GET,POST,PUT,DELETE
max_age = 86400
| Configuration Option | Description | Default Value | Notes |
|---|---|---|---|
| enabled | Enable or disable CORS support | false |
Set to true to enable CORS |
| allow_origins | Comma-separated list of allowed origins | * |
Use * to allow all origins or specify domains |
| allow_headers | Comma-separated list of allowed headers | Authorization,Content-Type |
Include Authorization for token-based auth |
| allow_methods | Comma-separated list of allowed HTTP methods | GET,POST,PUT,DELETE |
Specify methods used by frontend apps |
| max_age | Maximum age of preflight request cache (seconds) | 86400 |
Set to 0 to disable caching |
Note: When using
allow_origins = *, ensure that the allow_credentials setting is not enabled to avoid security risks.
Warning: Setting
allow_origins to * allows any domain to make requests to Grafana, which can be a security risk. Always restrict origins to known domains in production environments.
6. Using Data Source Proxy
| Property | Value | Description |
|---|---|---|
| datasource.proxy | true |
Enables proxying data source requests through Grafana server |
| datasource.timeout | 30s |
Timeout for proxy requests to data sources |
| datasource.maxConcurrentRequests | 100 |
Maximum concurrent proxy requests per data source |
Example: Enabling Data Source Proxy in Grafana Configuration
[datasource]
proxy = true
timeout = 30s
maxConcurrentRequests = 100
Note: Proxying is required when data sources are not accessible from the browser due to CORS restrictions or network isolation.
Warning: Enabling proxying can introduce latency and performance overhead. Ensure your Grafana instance has sufficient resources to handle proxy traffic.
7. Setting Password Requirements
| Property | Values | Description |
|---|---|---|
| password_policy.enabled | true / false |
Enables or disables password policy enforcement. |
| password_policy.min_length | 8 to 128 |
Minimum length of the password. |
| password_policy.require_uppercase | true / false |
Requires at least one uppercase letter. |
| password_policy.require_lowercase | true / false |
Requires at least one lowercase letter. |
| password_policy.require_numbers | true / false |
Requires at least one numeric character. |
| password_policy.require_special | true / false |
Requires at least one special character (e.g., !@#$%^&*). |
| password_policy.max_age_days | 0 to 365 |
Maximum age of a password before it must be changed. 0 = disabled. |
| password_policy.history_count | 0 to 20 |
Number of previous passwords that cannot be reused. |
Example: Enabling Password Policy
[password_policy]
enabled = true
min_length = 12
require_uppercase = true
require_lowercase = true
require_numbers = true
require_special = true
max_age_days = 90
history_count = 5
Note: These settings apply to all Grafana users and are enforced at login time.
8. Enabling Audit Logging
Audit logging in Grafana captures detailed information about user activities and system events for security monitoring and compliance purposes.
| Configuration Option | Description | Default Value | Notes |
|---|---|---|---|
| audit.enabled | Enables or disables audit logging. | false |
Set to true to enable audit logging. |
| audit.log_file | Path to the audit log file. | /var/log/grafana/audit.log |
Ensure the path is writable by the Grafana process. |
| audit.log_format | Format of the audit log entries. | json |
Supports json and csv. |
| audit.max_size | Maximum size of the audit log file before rotation. | 100MB |
Can be specified in MB, GB, etc. |
| audit.max_backups | Number of backup log files to keep. | 10 |
Older logs are deleted after this limit is reached. |
Example: Enabling Audit Logging in Grafana Configuration
[audit]
enabled = true
log_file = /var/log/grafana/audit.log
log_format = json
max_size = 100MB
max_backups = 10
Note: Audit logs can grow quickly in environments with high activity. Monitor disk space and configure log rotation accordingly.
9. Restricting Embedding
| Option | Values | Notes |
|---|---|---|
| grafana.ini [security] embeddable_iframe | false |
Disables embedding Grafana in iframes |
| grafana.ini [security] allowed_hosts | localhost,127.0.0.1 |
Whitelisted hosts for embedding |
Note: Setting
embeddable_iframe to false prevents Grafana dashboards from being embedded in external sites, enhancing security by mitigating potential XSS attacks.
10. Using Secret Management
Grafana supports integrating with external secret management systems to securely store and retrieve sensitive information like API keys, passwords, and tokens. This enhances security by avoiding the storage of plain-text secrets in configuration files or databases.
| Secret Backend | Description | Supported in Grafana |
|---|---|---|
| AWS Secrets Manager | Amazon's managed secret storage service. | NEW Grafana v10.3+ |
| Azure Key Vault | Microsoft's cloud-based secret management service. | NEW Grafana v10.3+ |
| HashiCorp Vault | Open-source secret management and data protection tool. | Grafana v9.0+ |
| GCP Secret Manager | Google Cloud's secret storage service. | NEW Grafana v10.3+ |
Example: Configuring HashiCorp Vault
[secret_backend]
backend = vault
[vault]
url = https://vault.example.com
token = s.xxxxxxxxxxxxxxxxxxxxxx
mount_path = grafana/secrets
Note: Ensure that the Grafana service account has appropriate permissions to access secrets in the configured backend.
Warning: Secrets stored in external backends are not encrypted at rest by Grafana itself. The encryption and access control must be handled by the secret management system.
11. Configuring Rate Limiting
| Option | Values | Description |
|---|---|---|
| rate_limit.enabled | true | false |
Enables or disables rate limiting. Default: false. |
| rate_limit.requests_per_minute | integer |
Maximum number of requests per minute allowed per user. Default: 120. |
| rate_limit.burst | integer |
Number of requests allowed to exceed the rate limit before blocking. Default: 10. |
| rate_limit.whitelist | string |
Comma-separated list of IP addresses or CIDR ranges to exempt from rate limiting. Default: "". |
Example: Enabling Rate Limiting in grafana.ini
[rate_limit]
enabled = true
requests_per_minute = 100
burst = 5
whitelist = 192.168.1.0/24, 10.0.0.1
Note: Rate limiting applies to all API endpoints and dashboard access. It is recommended to configure whitelisting for trusted internal services or IPs.
12. Setting Up Network Security
Example: Configure Grafana to listen on a specific IP and port
[server]
http_addr = 127.0.0.1
http_port = 3000
| Setting | Description | Default Value | Notes |
|---|---|---|---|
| server.http_addr | IP address for Grafana to bind to | 0.0.0.0 |
Use 127.0.0.1 for local access only |
| server.http_port | Port for Grafana to listen on | 3000 |
Change to a non-standard port for security |
Note: Binding to
0.0.0.0 makes Grafana accessible from any IP address, which is not recommended in secure environments.
Example: Enable HTTPS and configure SSL certificates
[server]
protocol = https
cert_file = /path/to/cert.pem
key_file = /path/to/key.pem
| Setting | Description | Default Value | Notes |
|---|---|---|---|
| server.protocol | Protocol to use for connections | http |
Set to https for encrypted connections |
| server.cert_file | Path to the SSL certificate file | |
Required when protocol = https |
| server.key_file | Path to the SSL private key file | |
Required when protocol = https |
Warning: Ensure that the certificate and key files are properly secured and have appropriate file permissions to prevent unauthorized access.
Example: Configure Grafana to use a reverse proxy with NGINX
server {
listen 443 ssl http2;
server_name grafana.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Network Security Best Practices
- Bind Grafana to a specific IP address (
127.0.0.1) for local access only. - Use HTTPS with valid SSL certificates to encrypt data in transit.
- Consider using a reverse proxy like NGINX for additional security features and load balancing.
- Ensure that sensitive configuration files (e.g., certificates) have restricted file permissions.