chronograf 使用 gitlab oauth2 認証

去年11月在試 chronograf 1.3 使用 gitlab oauth2 來認証登入時,沒試出來,就去 chronograf github repository 那邊發了 issue ,後來4月左右出了 1.4,開發者有回應,請我再試試看,昨天終於試出來了,下面紀錄一下過程與設定。

  1. 首先去 gitlab admin 頁面 (我用的是 gitlab 8.13.6) 新增 application,在 callback url 填入”http://your_chronograf_server:8888/oauth/generic/callback”。新增以後,把 “applicatoin id” and “secret” 記下來,後面會拿來填入 chronograf 的 “–generic-client-id ” / “–generic-client-secret “。
  2. 在啟動 chronograf 時,帶入以下參數 (gitlab_server 與 chronograf_server 請自行替換):
    • –generic-auth-url=http://gitlab_server/oauth/authorize?redirect_uri=http%3A%2F%2Fchronograf_server%3A8888%2Foauth%2Fgeneric%2Fcallback&response_type=code
    • –generic-token-url=http://gitlab_server/oauth/token?redirect_uri=http%3A%2F%2Fchronograf_server%3A8888%2Foauth%2Fgeneric%2Fcallback&grant_type=authorization_code
    • –generic-scopes=api
    • –token-secret=mysupersecret
    • –generic-api-url=http://gitlab_server/api/v3/user
  3. 到 chronograf 頁面時,就會看到 “Login with Generic”,點選按鈕,瀏覽器會帶到 gitlab 的登入頁面,在登入以後,會再帶回到 chronograf purgatory 頁面。

到這邊就算是成功了。但是我還沒去試怎麼去給予權限,讓使用者不要只能停留在 purgatory 頁面。

docker-gitlab 與 container registry

之前有試了兩三次,但都卡在憑證部份,昨天終於搞定了。

主要參考文件是 https://github.com/sameersbn/docker-gitlab/blob/master/docs/container_registry.md

第一步是產生憑證,不要用上面文章提供的 openssl 指令,用 https://gitlab.com/gitlab-org/gitlab-ce/issues/25967 所提供的:

# 假定是在 docker-compose.yml 所在的目錄下
mkdir -p certs
cd certs
openssl req -nodes -newkey rsa:4096 -keyout registry-auth.key -out registry-auth.csr -subj "/CN=gitlab-issuer"
openssl x509 -in registry-auth.csr -out registry-auth.crt -req -signkey registry-auth.key -days 3650

第二步是修改、調整原有的 docker-compose.yml

# gitlab
gitlab:
  environments:
    # ... other environment variables
    # ...
    # Registry
    - GITLAB_REGISTRY_ENABLED=true
    - GITLAB_REGISTRY_HOST=registry.example.com
    - GITLAB_REGISTRY_PORT=443
    - GITLAB_REGISTRY_API_URL=http://registry:5000
    - GITLAB_REGISTRY_KEY_PATH=/certs/registry-auth.key
    - SSL_REGISTRY_KEY_PATH=/certs/registry-auth.key
    - SSL_REGISTRY_CERT_PATH=/certs/registry-auth.crt
  volumes:
    # ... other volumes
    # ...
    # 將前面建立的 certs 資料夾掛載到 /certs
    - ./certs:/certs
  links:
    # ... other service links
    # ...
    - registry
registry:
  image: registry:2.4.1
  expose:
    - "5000"
  ports:
    - "5000:5000"
  volumes:
    - /var/gitlab/shared/registry:/registry
    - ./certs:/certs
  environment:
    - REGISTRY_LOG_LEVEL=info
    - REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/registry
    - REGISTRY_AUTH_TOKEN_REALM=https://git.example.com/jwt/auth
    # 如果你用的 gitlab 設定為 relative url root,那就是
    # - REGISTRY_AUTH_TOKEN_REALM=https://example.com/git/jwt/auth
    - REGISTRY_AUTH_TOKEN_SERVICE=container_registry
    - REGISTRY_AUTH_TOKEN_ISSUER=gitlab-issuer
    - REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE=/certs/registry-auth.crt
    - REGISTRY_STORAGE_DELETE_ENABLED=true

第三步是改 Apache 或 Nginx 的設定,Nginx 的設定可以參考 https://github.com/sameersbn/docker-gitlab/blob/master/docs/container_registry.md

我用的是 Apache ,所以我是參考 https://gist.github.com/dkarlovi/5f6ab416aa882086c7305b004b590dd4 來做修改,改完記得重新啟動 Apache 或 Nginx。

修改完以後,執行 docker-compose up ,應該就沒問題了。

我遇過以下問題:

  1. 瀏覽 https://git.example.com/group1/project1/container_registry 時,出現 Internal server error:主要是 gitlab 環境變數裡的 GITLAB_REGISTRY_KEY_PATH、SSL_REGISTRY_KEY_PATH、SSL_REGISTRY_CERT_PATH 跟 registry 環境變數裡的 REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE 沒有設定好,當然其他的也有可能,儘可能都檢查一次。
  2. docker login 失敗:其實也是上面提的那幾個環境變數沒設定好。

檢討之前為什麼沒能架設好,原因如下:

  1. 對 SSL 憑證不了解:我的 git.example.com / registry.example.com 都使用 SSL 憑證,但又跟 registry-auth 的憑證搞混,總的來說,總共三個憑證,git.example.com 一個,registry.example.com 一個,registry-auth 一個。gitlab.example.com/registry.example.com 的憑證是給網頁伺服器(Apache/Nginx)使用,Apache/Nginx 設定裡要設定,然後 docker-compose.yml gitlab 服務裡只用到 gitlab.example.com 的憑證,要用 SSL_KEY_PATH, SSL_CERTIFICATE_PATH 跟 SSL_DHPARAM_PATH 這三個環境變數來設定。而 registry-auth 則是 gitlab 服務與 registry 服務作 token 認証用的,主要是 gitlab 環境變數裡的 GITLAB_REGISTRY_KEY_PATH、SSL_REGISTRY_KEY_PATH、SSL_REGISTRY_CERT_PATH 跟 registry 環境變數裡的 REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE。
  2. Apache 的 SSL 設定錯誤:SSLCertificateFile, SSLCertificateKeyFile, SSLCertificateChainFile 跟 SSLCACertificateFile 都要設定,我少設了 SSLCertificateChainFile,導致 registry 服務去問 gitlab 時,有憑證錯而有 HTTP request fail 的問題。

找 git repository commits 裡的特定字串

因為在目前的程式碼裡找不到特定的字串,但是之前應該有,可能被移掉了,所以想找找之前提交的程式碼有沒有特定的字串。

請 Google 大神幫忙了一下,在 StackOverflow 上找到答案:How to grep (search) committed code in the git history? – Stack Overflow ,原來用 git grep 搭配 git rev-list 就可以做到:

# 找全部
git grep <regexp> $(git rev-list --all)

# 只找特定目錄下的
git grep <regexp> $(git rev-list --all -- lib/util) -- lib/util

在 javascript 裡將 dict/object 轉換為 xml

照一般的作法,會是用操作 DOM 的方式來產生出 XML,但這樣很繁瑣,找了好幾個函式庫,最後是找到 object-to-xml (Github網址),使用方法很簡單:

var objectToXML = require('object-to-xml');

var obj = { 
  '?xml version=\"1.0\" encoding=\"iso-8859-1\"?' : null,
  request : {
    '@' : {
      type : 'product',
      id : 12344556
    },
    '#' : {
      query : {
        vendor : 'redhat',
        name : 'linux'
      }
    }
  }
};

console.log(objectToXML(obj));
/*
<?xml version="1.0" encoding="iso-8859-1"?>
<request type="product" id="12344556">
  <query>
    <vendor>redhat</vendor>
    <name>linux</name>
  </query>
</request>
*/

在 ‘@’ 裡的,都是屬性,而在 ‘#’ 裡的則是子 element 。

在 typescript 裡,要用

import * as objectToXML from 'object-to-xml';

來匯入使用。

sqlite3 的 alter table

sqlite3 的 alter table 不能刪除 column 或是修改 column ,只能新增!!

是故,如果要修改或刪除,只能先將原來的 table 更名,然後重新建立,再使用 insert into + select 來插入。

語法示意如下:

BEGIN TRANSACTION;
CREATE TEMPORARY TABLE t1_backup(a,b);
INSERT INTO t1_backup SELECT a,b FROM t1;
DROP TABLE t1;
CREATE TABLE t1(a,b);
INSERT INTO t1 SELECT a,b FROM t1_backup;
DROP TABLE t1_backup;
COMMIT;

寫這篇,才想到 django migration 可能也因為這限制,所以當資料庫是 sqlite3 時,有刪除或更動 model 屬性時,並沒有真的更動資料表格。

Run ansible in gitlab runner

在 gitlab runner 裡想要執行 ansible playbook 進行佈署,幾個問題以及我的應對:

  1. ansible 的安裝:是可以自己加 ansible 的 package repository ,然後用 apt 安裝,但已經有好心人打包了裝好 ansible 的 docker image ,只要在 .gitlab-ci.yml 加入 image 設定即可:
    image: williamyeh/ansible:ubuntu14.04
  2. playbook 要放在哪裡?因為要直接在專案進行佈署,所以 playbook 也要放在專案裡,我在專案裡建立了一個 ansible 的目錄,把 playbook 放在這裡。
  3. 私密資料如何保存?gitlab 在專案設定裡提供了 variables,可以用來存放這些私密的資料,在 .gitlab-ci.yml 裡,只要用 $VAR_NAME 就可以使用這些變數。.gitlab-ci.yml 裡也可以自訂 variables ,但這些 variables 是進到 git repository 的,要視情況使用。
  4. Ansible 連到目的機器需要 SSH Key:這比較麻煩一點,好在 gitlab 有提供如何使用 SSH key 的文件,步驟很詳細,簡述如下:
    1. 在專案設定的 variables 裡新增有 SSH private key 的變數。
    2. 檢查 ssh-agent ,如果沒有就安裝 openssh-client
    3. 執行 ssh-agent
    4. 用 ssh-add 匯入第一個步驟所設定好的變數
    5. 在 ~/.ssh/config 裡加入不檢查 host key 的設定:
      Host *
          StrictHostKeyChecking no

參考資料:

compodoc

前兩天看到這篇:你寫的文件別人看得懂嗎?:compodoc ,所以想來試試看。

因為想放到 Jenkins 裡去自動產生 Angular App 的文件,所以想用 docker 來避免在 Jenkins 主機上安裝 compodoc 。

首先找到有沒有已經寫好的 docker image,很幸運,找到 sdvplurimedia/lea-pulse-compodoc – Docker Hub ,github repository 在 SDV-Plurimedia/docker-images: DockerFiles public ,從 Dockerfile 可以看出就只是簡單的繼承自 nodejs 的 image ,然後用 yarn 安裝 compodoc。

所以用 docker pull 拉到本地端,就可以用 docker run 來執行了,先看看有什麼參數:

docker run -it sdvplurimedia/lea-pulse-compodoc:latest compodoc --help

然後在專案目錄下建立 doc 目錄,用 docker run 將專案目錄掛載到 /src,輸出目錄掛到 /src/documentation,再執行:

docker run -v ${PWD}:/src -v ${PWD}/doc:/src/documentation -it sdvplurimedia/lea-pulse-compodoc:latest /bin/sh -c 'cd /src && compodoc -p tsconfig.json'

就可以在執行,並在 documentation 目錄裡找到 HTML 文件了。

Ansible 處理多主機不同密碼

用 Ansible 一陣子了,比較麻煩的地方是,主機不一定密碼都相同,簡單的方法當然是讓主機密碼都一樣,但這樣就降低了安全性。有沒有不需要改動密碼的方式呢?在網路上找了半天,找到這篇:ubuntu – Ansible: how to run a play with hosts with different passwords? – Stack Overflow ,裏面有個回應是建議使用 group_vars + ansible-vault + ansible_become_user/ansible_become_pass 來解決。

以下紀錄大致的步驟:

  1. 在 playbook 所在目錄或是 /etc/ansible 下建立 group_vars 資料夾 (以下簡稱 group_vars 資料夾)。
  2. 在 inventory 檔案裡,將相同密碼的主機編成一個群組,這裡假設群組名稱是 foo。
  3. 進入 group_vars 資料夾,用 ansible-vault create foo.yml ,這時候會詢問你 vault 的密碼,輸入完成以後,會開啟編輯器,請在裏面輸入
    ---
    ansible_become_user: "root"
    ansible_become_pass: "your_password"
  4. 存檔離開編輯器。
  5. 在輸入 ansible-playbook 或 ansible 指令時,帶 –ask-vault-pass 參數,也就是在執行時,會問你 vault 檔案的密碼,然後自動解密並讀入裏面的變數執行。

之後要編輯加密過的檔案,得用 ansible-vault edit foo.yml 才行。

參考資料:

Upgrade Jenkins plugins via SSH

之前都是啟用 CLI over remoting ,用 jenkins CLI 做更新,但前一陣子在更新 Jenkins 以後,開始該該叫,說這樣不安全。查了一下文件,發現可以用 SSH 來做。

  1. 在 http://jenkins/configureSecurity 裡啟用 random SSHD Port
  2. 在會使用 ssh 登入更新的使用者設定裡 (http://jenkins/user/YOUR_USER_NAME/configure),貼上 public key 。
  3. 參考並修改這個腳本,執行它就可以更新了。

wordpress 出現 Invalid post type 錯誤

今天進 wordpress ,選 All posts 後,就出現 Invalid post type. 的錯誤。先試著開啟 wordpress wp-admin/edit.php 看,發現一開始的檢查 $typenow 就導致錯誤 了,$typenow 是空的。

根據程式碼,試著在網址列加上 ?post_type=post ,能進入 All posts 了,但文章列表是空的。

  1. 上網找了一些文章,說是要移除 plugin ,但我試著移除了,沒有用。
  2. 對照目前的程式碼跟網路下載的 wordpress 4.8 程式碼,也幾乎是一樣的。
  3. 試著直接連線到資料庫看,資料表格一切正常,權限也都是正確的。
  4. 直接在 wp-config.php 裡加入
    define('WP_DEBUG', true);
    define('WP_DEBUG_DISPLAY', false);
    define('WP_DEBUG_LOG', true);
    

    ,然後看 wp-content/debug.log ,終於找到一點蛛絲馬跡。

看來是因為 wp-include/vars.php 有問題,裏面用 preg_match 檢查 _SERVER[‘PHP_SELF’] 時,因為 match 不到而出錯,猜想這可能連到影響到後續的 $typenow 有問題。根據這個線索去推敲,PHP 應該沒問題,察看了 php-fpm 的設定,也沒問題。後來找到這篇:php – Wrong SCRIPT_FILENAME in Apache 2.4.26 – Stack Overflow,再循線看到這篇:php – Wrong SCRIPT_FILENAME in Apache 2.4.26 – Stack Overflow才知道可能是 Apache 問題,察看了 pacman 的 log,果然前幾天有更新,但是因為沒有重新啟動,所以都沒發現問題。在設定裡補上

ProxyFCGIBackendType GENERIC

以後,重新啟動 Apache 就沒問題了。