Secure Grafana Loki
จากบทความก่อนที่เราได้ลองสร้าง Simple Centralized Logs Monitoring with Grafana Loki กันไปในบทความที่แล้ว แต่ยังมีเรื่องสำคัญที่ยังไม่ได้จัดการก็คือเรื่อง Security นั่นเอง ในบทความนี้เรามาทำการ improve Security ให้กับ Centralized Logs Monitoring ของเรากันครับ
Theory
ในบทความนี้เราจะใช้เทคนิคในการทำ Security ให้กับ Centralized Logs Monitoring ดังต่อไปนี้
TLS/HTTPS: Encrypt Communication
HTTP
เป็น protocol ที่ใช้ในการ fetching resource จาก server ปลายทาง เช่น HTML documents ซึ่งเป็น protocol หลักที่ใช้ใน Web browser หรืออาจเรียกได้ว่าเป็น client-server protocol ที่ใช้กันอย่างแพร่หลายในปัจจุบัน
โดยการติดต่อสื่อสารระหว่าง client-server ที่ใช้ protocol นี้ จะยังไม่ถูกเข้ารหัส ซึ่งมีความเสี่ยงในการถูกดักจับข้อมูล (man-in-the-middle attacks) จึงได้มีการพัฒนาเป็น HTTPS protocol ขึ้นมาเพื่อช่วยในการเข้ารหัสข้อความในการติดต่อสื่อสารระหว่าง client-server
TLS (Transport Layer Security)
TLS เป็น protocol ที่ช่วยในการเข้ารหัส โดยส่วนใหญ่จะรู้จักกันในชื่อ SSL (Secure Sockets Layer) ซึ่ง HTTP protocol นี้จะใช้ TLS มาช่วยในการเข้ารหัสจึงกลายเป็น HTTPS protocol หรือที่เรียกว่า HTTP over TLS ที่ใช้งานกันอย่างแพร่หลายในทุกวันนี้
HTTPS ทำงานยังไง?
การทำงานของ HTTPS จะทำการเข้ารหัสการติดต่อสื่อสารในรูปแบบของ asymmetric public key infrastructure ซึ่งจะประกอบไปด้วย keys ทั้งหมด 2 ประเภท ได้แก่
- Private key - key นี้จะอยู่กับเจ้าของ server เพื่อใช้ในการถอดข้อมูลที่ทำการเข้ารหัส ซึ่งตามบทความนี้จะเก็บอยู่ใน Grafana Loki Gateway
- Public key - key นี้จะใช้สำหรับใครก็ตามที่ต้องการติดต่อสื่อสารกับ server ซึ่งตามบทความนี้ตัว Promtail agent จะใช้ Public key ของ Grafana Loki Gateway ในการเข้ารหัสข้อมูล แล้วส่งข้อมูล Logs ให้ต่อไป
Reverse Proxy (NGINX) Gateway: Access Control
ในบทความที่แล้วเราได้ implement Grafana Loki ในรูปแบบของ Simple Scalable ซึ่งจะมีการ deploy ตัว Grafana Loki Gateway (Nginx) เป็น reverse proxy คั่นกลางก่อนที่จะเข้าถึง Grafana Loki โดยตัว Gateway นี้จะทำการ enforce ในการทำ authentication requests ก่อนที่จะเข้าถึง Grafana Loki
Basic Authentication: Access Control
เป็นการยืนยันตัวตนในการเข้าถึง Grafana Loki Server โดยจะใช้หลักการยืนยันตัวตนในรูปแบบของ username และ password ในการเข้าถึง resource ซึ่งจะทำผ่าน Grafana Loki Gateway
Practice
ใน Lab นี้เราจะทำการ configure ให้ Promtail และ Grafana ทำการติดต่อสื่อสารกับ Grafana Loki ด้วย Protocol HTTPS และมีการทำ Authentication ก่อนเข้าถึง Grafana Loki
Lab นี้จะใช้ Self-signed certificate ในการทำ HTTPS ซึ่งเป็นการใช้สำหรับ Network Private ระหว่าง Promtail agent, Grafana และ Grafana Loki เท่านั้น จึงต้องมีการทำ Trust certificate เพื่อใช้ในการติดต่อสื่อสารกันระหว่าง Servers
แต่ไม่ควรนำ Self-signed certificate ที่สร้างนี้ไปใช้ในการติดต่อสื่อสารแบบ client server ที่ให้ user ใช้ในการเข้าถึง เช่น การเข้าผ่าน Web Browser เนื่องจากอาจเป็นความเสี่ยงในกรณีถูกปลอมแปลง certificate ได้
Grafana Loki
ทำการสร้าง Self-Signed TLS Certificate เพื่อใช้ในการติดต่อสื่อสารระหว่าง Promtail กับ Grafana Loki ผ่าน Protocol HTTPS ซึ่งตามตัวอย่างเราจะกำหนดอายุไว้ที่ 1 ปี โดยเราจะ reuse code จาก repository Simple Centralized Logs Monitoring with Grafana Loki
git clone [email protected]:nestpractice/observability-simpleloki.git cd observability-simpleloki mkdir -p certs auth cat > certs/cert.conf <<EOF [req] default_bits = 2048 prompt = no default_md = sha256 distinguished_name = dn req_extensions = req_ext [dn] CN = loki-gateway [req_ext] subjectAltName = @alt_names [alt_names] DNS.1 = loki-gateway DNS.2 = localhost IP.1 = <GRAFANA_LOKI_IP_ADDRESS> EOF openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout certs/loki.key -out certs/loki.crt -config certs/cert.conf -extensions req_ext
จากนั้นทำการสร้าง Basic Auth Username Password เพื่อใช้ในการ Authentication ในการเข้าถึง Grafana Loki
docker run --rm -it httpd:alpine htpasswd -Bbn username password > auth/htpasswd
ตั้งค่า
nginx.conf
ให้รับ request HTTPS ผ่าน port 443 (Container Port) ใน path ของการ read และ write ใน Grafana Lokiconfig/nginx.conferror_log /dev/stderr; pid /tmp/nginx.pid; worker_rlimit_nofile 8192; events { worker_connections 4096; } http { default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] $status ' '"$request" $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /dev/stderr main; sendfile on; tcp_nopush on; upstream read { server loki-read:3100; } upstream write { server loki-write:3100; } upstream cluster { server loki-read:3100; server loki-write:3100; } server { listen 80; listen 3100; listen 443 ssl; ssl_certificate /etc/nginx/certs/loki.crt; ssl_certificate_key /etc/nginx/certs/loki.key; location = /ring { proxy_pass http://cluster$request_uri; } location = /memberlist { proxy_pass http://cluster$request_uri; } location = /config { proxy_pass http://cluster$request_uri; } location = /metrics { proxy_pass http://cluster$request_uri; } location = /ready { proxy_pass http://cluster$request_uri; } location = /loki/api/v1/push { auth_basic "Restricted"; auth_basic_user_file /etc/nginx/auth/htpasswd; proxy_pass http://write$request_uri; } location = /loki/api/v1/tail { proxy_pass http://read$request_uri; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } location ~ /loki/api/.* { auth_basic "Restricted"; auth_basic_user_file /etc/nginx/auth/htpasswd; proxy_pass http://read$request_uri; } } }
เปลี่ยนแปลง configuration loki-gateway service ใน
docker-compose.yaml
filedocker-compose.yamlservices: ... loki-gateway: image: nginx:latest volumes: - ./config/nginx.conf:/etc/nginx/nginx.conf - ./certs:/etc/nginx/certs - ./auth:/etc/nginx/auth ports: - "8443:443" - "8080:80" - "3100" networks: - loki ...
ทำการ run Grafana Loki ขึ้นมาใหม่
docker compose -f simple-loki/docker-compose.yaml up -d
ทำการแก้ไข Datasource ใน Grafana ให้ใช้ HTTPS, BasicAuth ในการเข้าถึง Grafana Loki และทำการ Add self-signed certificate จากไฟล์
loki.crt
ที่เราได้ทำการสร้างตามขั้นตอนที่ 1
Promtail
นำไฟล์
loki.crt
ที่ได้ทำการสร้างไว้บน Grafana Loki server ส่งไปที่ Server ที่เราได้ลง Promtail ไว้ ตาม Lab นี้ก็คือweb01
และdb01
แล้วทำการ restart servicesudo cp /tmp/loki.crt /usr/local/share/ca-certificates/loki.crt sudo update-ca-certificates
แก้ไข Promtail configuration ทั้ง 2 เครื่อง และ restart service
/etc/promtail/promtail-config.yaml... clients: - url: https://<GRAFANA_LOKI_IP_ADDRESS>:8443/loki/api/v1/push tenant_id: servers basic_auth: username: admin password: demoLoki tls_config: ca_file: /usr/local/share/ca-certificates/loki.crt insecure_skip_verify: false ...
sudo systemctl restart promtail
Verification
กลับไปที่ Grafana Loki server แล้วทำการเช็ค Log ว่าสามารถเชื่อมต่อไปยังรับ Logs จาก Promtail ได้หรือไม่ หาก return 2xx
ทั้งขา read (GET
) และ write (POST
) เป็นอันใช้งานได้
Summary
จากที่ได้ทำ Lab กันมาแล้วนั้น จะเห็นได้ว่าเราสามารถทำให้ระบบ Centralized Logs Monitoring ปลอดภัยมากขึ้น แต่ไม่ได้หมายความว่าระบบจะมั่นคงปลอดภัยได้ 100% แต่สิ่งที่เราได้ทำกันใน Lab นี้นั้น มันคือการลดความเสี่ยงที่อาจจะเกิดขึ้นจากผู้ไม่หวังดีที่เข้ามาโจมตีระบบเราได้ครับ
ทั้งนี้ การทำเทคนิคเหล่านี้อาจจะทำได้ยากขึ้น ถ้าหากเรามี Servers ที่ต้องการเก็บ Logs จำนวนมาก เราอาจจะต้องมีการใช้เครื่องมือการช่วยเหลือในการทำ Automation อย่างเช่น Ansible เข้ามาช่วยในการทำ implement ให้ง่ายยิ่งขึ้น (ไว้มาติดตามกันในบทความหน้านะครับ)