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.
Transport Layer Security (TLS) encrypts communication between clients and Grafana, and between Grafana and external services. This guide covers TLS configuration for various components.
Overview
Grafana supports TLS/SSL for:
- HTTPS server configuration
- gRPC server communication
- LDAP connections
- OAuth provider connections
- Database connections
- SMTP email delivery
- Datasource connections
HTTPS Server Configuration
Configure Grafana to serve content over HTTPS.
Basic HTTPS Setup
[server]
# Use HTTPS protocol
protocol = https
# Certificate and key files
cert_file = /path/to/grafana.crt
cert_key = /path/to/grafana.key
# Certificate passphrase (if encrypted)
cert_pass = your_passphrase
# Enable automatic certificate reload
certs_watch_interval = 1h
Reference: conf/defaults.ini:40-80
TLS Version Configuration
Specify minimum TLS version:
[server]
# Minimum TLS version
# Options: TLS1.2, TLS1.3
min_tls_version = "TLS1.2"
Reference: conf/defaults.ini:44
Grafana supports:
- PEM format: Standard ASCII-armored certificates (most common)
- PKCS#12: Binary format (requires conversion to PEM)
Self-Signed Certificates
For development environments:
# Generate self-signed certificate
openssl req -x509 -newkey rsa:4096 \
-keyout grafana-key.pem -out grafana-cert.pem \
-days 365 -nodes \
-subj "/CN=localhost"
# Configure Grafana
[server]
protocol = https
cert_file = /path/to/grafana-cert.pem
cert_key = /path/to/grafana-key.pem
Certificate Reload
Grafana can automatically reload certificates without restart:
[server]
# Watch certificate files for changes
certs_watch_interval = 1h
Reference: conf/defaults.ini:80
HTTP Strict Transport Security (HSTS)
Enforce HTTPS connections with HSTS headers.
HSTS Configuration
[security]
# Enable HSTS
strict_transport_security = true
# HSTS max age (seconds)
strict_transport_security_max_age_seconds = 86400
# Include subdomains
strict_transport_security_subdomains = false
# Enable preload
strict_transport_security_preload = false
Reference: conf/defaults.ini:422-433
HSTS tells browsers to:
- Always use HTTPS for the domain
- Reject invalid certificates
- Prevent SSL stripping attacks
HSTS Best Practices
- Start with short max-age: Test with 300 seconds initially
- Increase gradually: Move to 86400 (1 day), then 31536000 (1 year)
- Enable preload carefully: Only for production domains you control
- Test thoroughly: HSTS can’t be easily reverted
gRPC Server TLS
Secure gRPC communication between Grafana components.
gRPC TLS Configuration
[grpc_server]
network = "tcp"
address = "127.0.0.1:10000"
# Enable TLS
use_tls = true
# Certificate files
cert_file = /path/to/grpc-cert.pem
cert_key = /path/to/grpc-key.pem
Reference: conf/defaults.ini:113-121
LDAP TLS Configuration
Secure LDAP connections with TLS/SSL.
LDAPS Configuration
In ldap.toml:
[[servers]]
host = "ldap.example.com"
port = 636
# Use SSL (LDAPS)
use_ssl = true
# Or use StartTLS on standard port
# port = 389
# start_tls = true
# Certificate validation
ssl_skip_verify = false
# Minimum TLS version
min_tls_version = "TLS1.2"
# Allowed TLS ciphers
tls_ciphers = [
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
]
# Root CA certificate
root_ca_cert = "/path/to/ca.crt"
# Client certificate (mTLS)
client_cert = "/path/to/client.crt"
client_key = "/path/to/client.key"
Implementation: pkg/services/ldap/settings.go:35-52
LDAP TLS Options
- use_ssl: Connect via LDAPS (port 636)
- start_tls: Upgrade connection to TLS (port 389)
- ssl_skip_verify: Skip certificate verification (insecure)
- min_tls_version: Minimum TLS version (TLS1.2, TLS1.3)
- tls_ciphers: Allowed cipher suites
- root_ca_cert: CA certificate for server verification
- client_cert/client_key: Client certificate for mutual TLS
Reference: pkg/services/ldap/settings.go:39-52
Cipher Suite Configuration
The TLS cipher configuration is handled by utility functions:
// Convert TLS version string to constant
server.MinTLSVersionID, err = util.TlsNameToVersion(server.MinTLSVersion)
// Convert cipher names to IDs
server.TLSCipherIDs, err = util.TlsCiphersToIDs(server.TLSCiphers)
Reference: pkg/services/ldap/settings.go:182-194
OAuth Provider TLS
Secure communication with OAuth identity providers.
OAuth TLS Settings
[auth.generic_oauth]
enabled = true
# TLS configuration
tls_skip_verify_insecure = false
tls_client_cert = /path/to/client.crt
tls_client_key = /path/to/client.key
tls_client_ca = /path/to/ca.crt
# OAuth URLs (should use HTTPS)
auth_url = https://provider.com/oauth/authorize
token_url = https://provider.com/oauth/token
api_url = https://provider.com/api/user
Reference: conf/defaults.ini:937-940
The OAuth strategy loads TLS settings from configuration:
result := map[string]any{
"tls_client_cert": section.Key("tls_client_cert").Value(),
"tls_client_key": section.Key("tls_client_key").Value(),
"tls_client_ca": section.Key("tls_client_ca").Value(),
"tls_skip_verify_insecure": section.Key("tls_skip_verify_insecure").MustBool(false),
}
Reference: pkg/services/ssosettings/strategies/oauth_strategy.go:99-102
Mutual TLS (mTLS) for OAuth
Some OAuth providers require client certificates:
[auth.azuread]
enabled = true
# Client certificate authentication
tls_client_cert = /path/to/client.crt
tls_client_key = /path/to/client.key
tls_client_ca = /path/to/ca.crt
Database TLS
Secure database connections with TLS.
PostgreSQL TLS
[database]
type = postgres
host = postgres.example.com:5432
name = grafana
user = grafana
password = password
# SSL mode
# Options: disable, require, verify-ca, verify-full
ssl_mode = verify-full
# Enable SNI
ssl_sni = 1
# Certificate files
ca_cert_path = /path/to/ca.crt
client_key_path = /path/to/client.key
client_cert_path = /path/to/client.crt
# Server certificate name
server_cert_name = postgres.example.com
Reference: conf/defaults.ini:174-190
MySQL TLS
[database]
type = mysql
host = mysql.example.com:3306
name = grafana
user = grafana
password = password
# SSL mode
# Options: true, false, skip-verify
ssl_mode = true
# Certificate files
ca_cert_path = /path/to/ca.crt
client_key_path = /path/to/client.key
client_cert_path = /path/to/client.crt
Reference: conf/defaults.ini:175-190
SMTP TLS
Secure email delivery with TLS.
SMTP TLS Configuration
[smtp]
enabled = true
host = smtp.example.com:587
user = grafana@example.com
password = password
# Skip certificate verification (not recommended)
skip_verify = false
# Certificate files
cert_file = /path/to/client.crt
key_file = /path/to/client.key
# StartTLS policy
# Options: OpportunisticStartTLS, MandatoryStartTLS, NoStartTLS
startTLS_policy = MandatoryStartTLS
Reference: conf/defaults.ini:1137-1150
StartTLS Policies
- NoStartTLS: No TLS (insecure)
- OpportunisticStartTLS: Use TLS if available
- MandatoryStartTLS: Require TLS, fail if unavailable
Datasource TLS
Secure connections to datasources.
Datasource TLS Settings
Most datasources support TLS configuration in their settings:
{
"url": "https://prometheus.example.com",
"jsonData": {
"tlsAuth": true,
"tlsAuthWithCACert": true,
"tlsSkipVerify": false,
"serverName": "prometheus.example.com"
},
"secureJsonData": {
"tlsClientCert": "-----BEGIN CERTIFICATE-----...",
"tlsClientKey": "-----BEGIN PRIVATE KEY-----...",
"tlsCACert": "-----BEGIN CERTIFICATE-----..."
}
}
Common Datasource TLS Options
- tlsAuth: Enable TLS client authentication
- tlsAuthWithCACert: Verify server certificate with CA
- tlsSkipVerify: Skip certificate verification (insecure)
- serverName: Expected server name in certificate
- tlsClientCert: Client certificate (PEM)
- tlsClientKey: Client private key (PEM)
- tlsCACert: CA certificate (PEM)
HTTP Client TLS
Grafana’s HTTP client provider handles TLS for outgoing requests.
Implementation: pkg/infra/httpclient/httpclientprovider/
TLS Configuration
The HTTP client supports:
- Custom CA certificates
- Client certificates (mTLS)
- TLS version restrictions
- Cipher suite selection
- Certificate verification
TLS Handshake Timeout
[dataproxy]
# TLS handshake timeout
tls_handshake_timeout_seconds = 10
Reference: conf/defaults.ini:264
Content Security Policy
Control resource loading with CSP headers.
CSP Configuration
[security]
# Enable CSP
content_security_policy = true
# CSP template
content_security_policy_template = """script-src 'self' 'unsafe-eval' 'unsafe-inline' 'strict-dynamic' $NONCE;object-src 'none';font-src 'self';style-src 'self' 'unsafe-inline' blob:;img-src * data:;base-uri 'self';connect-src 'self' grafana.com ws://$ROOT_PATH wss://$ROOT_PATH;manifest-src 'self';media-src 'none';form-action 'self';"""
# Report-only mode for testing
content_security_policy_report_only = false
content_security_policy_report_only_template = """..."""
Reference: conf/defaults.ini:444-460
CSP for HTTPS
Ensure CSP allows secure WebSocket connections:
connect-src 'self' wss://$ROOT_PATH;
Certificate Management
Certificate Generation
Self-Signed Certificate
# Generate private key
openssl genrsa -out grafana-key.pem 4096
# Generate certificate signing request
openssl req -new -key grafana-key.pem -out grafana-csr.pem \
-subj "/CN=grafana.example.com"
# Generate self-signed certificate
openssl x509 -req -in grafana-csr.pem \
-signkey grafana-key.pem \
-out grafana-cert.pem \
-days 365
Certificate with SAN
# Create config file
cat > san.cnf <<EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[req_distinguished_name]
CN = grafana.example.com
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = grafana.example.com
DNS.2 = grafana.local
IP.1 = 10.0.0.10
EOF
# Generate certificate
openssl req -x509 -newkey rsa:4096 \
-keyout grafana-key.pem -out grafana-cert.pem \
-days 365 -nodes \
-config san.cnf -extensions v3_req
Certificate Verification
# Verify certificate
openssl x509 -in grafana-cert.pem -text -noout
# Check certificate dates
openssl x509 -in grafana-cert.pem -noout -dates
# Verify certificate chain
openssl verify -CAfile ca.crt grafana-cert.pem
# Test TLS connection
openssl s_client -connect grafana.example.com:443
Certificate Renewal
With certificate watching enabled, Grafana automatically reloads certificates:
[server]
certs_watch_interval = 1h
Manual reload (if watching is disabled):
# Replace certificates
cp new-cert.pem /path/to/grafana.crt
cp new-key.pem /path/to/grafana.key
# Restart Grafana
systemctl restart grafana-server
CSRF Protection
Cross-Site Request Forgery protection works with TLS.
CSRF Configuration
[security]
# Enable CSRF checking even without login cookie
csrf_always_check = false
# Additional trusted headers
csrf_additional_headers = X-Forwarded-Host
# Trusted origins
csrf_trusted_origins = grafana.example.com
Reference: conf/defaults.ini:462-463
Implementation: pkg/middleware/csrf/csrf.go
The CSRF middleware validates the Origin header:
func (c *CSRF) check(r *http.Request) error {
// Get Origin header
o := r.Header.Get("Origin")
// Parse origin URL
originURL, err := url.Parse(o)
origin := originURL.Hostname()
// Check if origin is trusted
for trustedOrigin := range c.trustedOrigins {
if trustedOrigin == origin {
return nil
}
}
// Verify origin matches request host
if origin != requestHost {
return errors.New("origin not allowed")
}
}
Reference: pkg/middleware/csrf/csrf.go:71-141
Additional security headers for HTTPS deployments.
X-Content-Type-Options
[security]
x_content_type_options = true
Prevents MIME type sniffing.
Reference: conf/defaults.ini:438
X-XSS-Protection
[security]
x_xss_protection = true
Enables browser XSS protection.
Reference: conf/defaults.ini:442
Best Practices
1. Always Use TLS in Production
[server]
protocol = https
min_tls_version = "TLS1.2"
2. Use Strong Cipher Suites
Prefer modern, secure cipher suites:
tls_ciphers = [
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
]
3. Verify Certificates
Never skip certificate verification in production:
# Bad
tls_skip_verify_insecure = true
ssl_skip_verify = true
# Good
tls_skip_verify_insecure = false
ssl_skip_verify = false
ca_cert_path = /path/to/ca.crt
4. Use Certificate Watching
Enable automatic certificate reload:
[server]
certs_watch_interval = 1h
5. Implement HSTS
Enforce HTTPS in browsers:
[security]
strict_transport_security = true
strict_transport_security_max_age_seconds = 31536000
6. Secure Cookie Settings
[security]
cookie_secure = true
cookie_samesite = strict
Reference: conf/defaults.ini:414-417
7. Monitor Certificate Expiration
Set up alerts for certificate expiration:
# Check certificate expiration
openssl x509 -in grafana-cert.pem -noout -enddate
# Alert if expires in < 30 days
days_until_expiry=$(( ($(date -d "$(openssl x509 -in grafana-cert.pem -noout -enddate | cut -d= -f2)" +%s) - $(date +%s)) / 86400 ))
if [ $days_until_expiry -lt 30 ]; then
echo "Certificate expires in $days_until_expiry days!"
fi
8. Use Mutual TLS (mTLS) for Services
For service-to-service communication:
[grpc_server]
use_tls = true
cert_file = /path/to/server.crt
cert_key = /path/to/server.key
# Require client certificates
Troubleshooting
Certificate Issues
# Test HTTPS connection
curl -v https://grafana.example.com
# Test with custom CA
curl --cacert ca.crt https://grafana.example.com
# Ignore certificate errors (testing only)
curl -k https://grafana.example.com
TLS Handshake Errors
Common causes:
- Certificate expired
- Wrong certificate hostname
- Missing intermediate certificates
- Cipher suite mismatch
- TLS version not supported
Debug Logging
[log]
filters = http.server:debug
OpenSSL Debugging
# Test TLS connection with detailed output
openssl s_client -connect grafana.example.com:443 \
-showcerts -state -debug
# Test specific TLS version
openssl s_client -connect grafana.example.com:443 -tls1_2
# List supported ciphers
openssl s_client -connect grafana.example.com:443 -cipher 'HIGH'