Grafana 7.5.15 / 8.3.5 で追加されたセキュリティ対策で発生する問題を回避する

# はじめに

<a href="https://console.cloud.google.com">GCP</a>のCloud Shell環境(ウェブでプレビュー)でGrafanaの動作確認をしていたら「origin not allowed」というエラーが出るようになってしまった。

![CSRF.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/cbe2139b-b301-6e7f-354b-8c721f2b158c.png)

# 原因

同じような状況を調べたところ、<a href="https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA">CSRF</a>対策の機能が追加されたことで、GCPのCloud Shell環境では正常に動作しなくなったことがわかった。

https://community.grafana.com/t/after-update-to-8-3-5-origin-not-allowed-behind-proxy/60598

https://github.com/grafana/grafana/issues/45117

https://grafana.com/blog/2022/02/08/grafana-7.5.15-and-8.3.5-released-with-moderate-severity-security-fixes/

## パケットキャプチャ

tcpdumpコマンドでブラウザからGrafanaへのアクセスを確認したところ、HostヘッダとOriginヘッダの値が異なっている(一致していない)ことを確認できた。

Host: 127.0.0.1:3001
Origin: https://3001-cs-911836254277-default.cs-asia-east1-jnrc.cloudshell.dev

※ Cloud Shell環境でエディタ(Eclipse Theia)を開くとポート:3000が使用されてしまい、Grafanaのデフォルトのポート番号と重複するため、起動時にポート:3001に変更しています。

![cloud_shell_theia.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/d3772825-e5a5-2bea-ae54-2d355e4e641c.png)

# 解決方法

## 1. ngrokを使用する

Cloud Shell環境のウェブでプレビューを使用しない方法です。

![スクリーンショット 2022-07-23 23.34.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/47c934b1-f373-f11a-b14c-1b3da867509e.png)

### 手順

ngrokのホームページへアクセスし、「Sign up for free」を押してアカウントを登録します。

![スクリーンショット 2022-07-23 23.41.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/e8351acf-135b-42d9-587a-ec11f68974e9.png)

アカウント登録後、「Login」を押してログインします。

![スクリーンショット 2022-07-23 23.41.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/7b64147b-bef4-9c22-09f8-39eaee7cf829.png)

![スクリーンショット 2022-07-23 23.43.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/9bdaa951-9943-9b31-6ef6-2deb55262de7.png)

ログイン後、アクセストークンを取得します。(ngrokのダウンロードとインストールはコマンドラインから行います)
左側のメニューから「Your Authtoken」を選択します。

![スクリーンショット 2022-07-23 23.44.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/34c3398b-4630-669f-1db1-6cd2cd5464e5.png)

アクセストークンの情報を控えます。

![スクリーンショット 2022-07-23 23.44.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/df06d5cc-8e04-68ac-c660-f2c73236dfed.png)

ngrokのソフトウェア(バイナリファイル)をダウンロードして解凍します。

```bash
$ wget https://bin.equinox.io/c/bNyj1mQVY4c/ngrok-v3-stable-linux-amd64.tgz

$ tar xvzf ngrok-v3-stable-linux-amd64.tgz
```

アクセストークンの情報を登録します。

```bash
$ ./ngrok config add-authtoken [アクセストークンの情報]
```

ngrokを起動します。

```bash
$ ./ngrok http 3001
```

起動後の画面で、「Forwarding」に表示されるURLへアクセスします。(URLは起動する度に変わります)

```bash
ngrok                                                                                                                           (Ctrl+C to quit)
                                                                                                                                                
Hello World! https://ngrok.com/next-generation                                                                                                  
                                                                                                                                                
Session Status                online                                                                                                            
Account                       Ayachika Kitazaki (Plan: Free)                                                                                    
Version                       3.0.6                                                                                                             
Region                        United States (us)                                                                                                
Latency                       -                                                                                                                 
Web Interface                 http://127.0.0.1:4040                                                                                             
Forwarding                    https://78ff-34-81-87-94.ngrok.io -> http://localhost:3001                                                        
                                                                                                                                                
Connections                   ttl     opn     rt1     rt5     p50     p90                                                                       
                              0       0       0.00    0.00    0.00    0.00                
```

## 2. Reverse Proxy (Nginx)を使用する

Grafana公式ではReverse Proxy(Nginx または Apache)を使用して回避する方法が提示されています。

https://grafana.com/tutorials/run-grafana-behind-a-proxy/

![スクリーンショット 2022-07-23 23.53.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/01dc1020-8b17-4cfd-febc-f3d628bf9c25.png)

### 手順

NginxとGrafanaのコンフィグファイルに設定を追加する必要があります。
NginxとGrafanaをDockerでインストールする前提で設定例を示します。

Nginxのコンフィグ(default.conf)

```text:default.conf
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location /grafana/ {
        rewrite  ^/grafana/(.*)  /$1 break;
        proxy_set_header Host $http_host;
        proxy_set_header Origin http://$http_host;
        proxy_pass http://host.docker.internal:3001/;    }

    location /grafana/api/live/ {
        rewrite  ^/grafana/(.*)  /$1 break;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $http_host;
        proxy_set_header Origin http://$http_host;
        proxy_pass http://host.docker.internal:3001/;
    }

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}
```

Grafanaのコンフィグ(grafana.ini)
※ コンフィグファイルのサイズが大きいため、Serverカテゴリの変更箇所だけ記載します。
- ポート番号(http_port)はGCPのCloud Shell環境でエディタ(Eclipse Theia)を開くとポート:3000が使用されてしまうため、ポート:3001に変更しています。
- ドメイン(domain)はDocker環境からホスト環境(別のDocker環境)のGrafanaへアクセスするため、設定しています。
- ルートURL(root_url)はNginxのルート(/)からの相対パス(/grafana)でアクセスするため、設定しています。
- サブパス(serve_from_sub_path)はNginxのルート(/)からの相対パス(/grafana)でアクセスするため、設定しています。

```text:grafana.ini
#################################### Server ####################################
[server]
# The http port  to use
http_port = 3001

# The public facing domain name used to access grafana from a browser
domain = host.docker.internal

# The full public facing url you use in browser, used for redirects and emails
# If you use reverse proxy and sub path specify full url (with sub path)
root_url = %(protocol)s://%(domain)s:%(http_port)s/grafana/

# Serve Grafana from subpath specified in `root_url` setting. By default it is set to `false` for compatibility reasons.
serve_from_sub_path = true
```

次にdockerコマンドでNginxとGrafanaをインストールします。
コンフィグファイルはホームディレクトリにある前提で実行します。

```bash
$ docker run -d -p 8080:80 --name nginx --add-host=host.docker.internal:host-gateway -v `pwd`/default.conf:/etc/nginx/conf.d/default.conf nginx

$ docker run -d -p 3001:3001 --name=grafana -v `pwd`/grafana.ini:/etc/grafana/grafana.ini grafana/grafana:latest
```

正常に起動しているか確認します。

```bash
$ docker ps
CONTAINER ID   IMAGE                    COMMAND                  CREATED         STATUS         PORTS                              NAMES
a6222957eb05   grafana/grafana:latest   "/run.sh"                3 minutes ago   Up 3 minutes   3000/tcp, 0.0.0.0:3001->3001/tcp   grafana
049eb4852b68   nginx                    "/docker-entrypoint.…"   3 minutes ago   Up 3 minutes   0.0.0.0:8080->80/tcp               nginx
```

ブラウザでプレビュー(ポート:8080)を実行します。

![ウェブでプレビュー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/0ceeeda3-fdd3-6523-c269-fdb432ba2c57.png)

Nginxの初期画面(index.html)が表示されます。

![スクリーンショット 2022-07-24 0.34.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/b55c77ba-ece2-fa71-7ac0-eb3508e7dd64.png)

URLの最後に/grafanaを付けてアクセスします。

```bash
https://8080-cs-911836254277-default.cs-asia-east1-jnrc.cloudshell.dev/grafana/
```

![スクリーンショット 2022-07-24 0.40.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/4138fcb5-6f79-ce12-2a4a-b0fb030f9eb2.png)

### (参考)

デフォルトのコンフィグファイルをDocker環境からコピーしたい場合、次のコマンドを実行します。

```bash
$ docker cp nginx:/etc/nginx/conf.d/default.conf .

$ docker cp grafana:/etc/grafana/grafana.ini .
```