それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

はてなブログが検索インデックスされない問題。

はてなブログが検索インデックスされない

自分のブログを備忘録としてつけているが、Googleで検索しても検索されないのである。

sitemap は分割された

はてなブログのSitemapは、年月に分割されたが、最上位を登録すれば大丈夫なはずである。

それでも、検索されないのである。

Googleの問題か、はてなブログの問題かわからなくなる。

全部登録してみた。

periodical.xmlサイトマップを全部登録してやった。API経由でサクッと登録した。

読み込み不能がいっぱい出てくる。

f:id:takuya_1st:20220405020907p:plain

ファイル(URL)にはアクセス可能だけど、Googleはアクセスできないとおっしゃるのである。

原因がわからない。もしかして、初回アクセスになってて時間がかかりすぎ問題でしょうか。

定期的に実行してみる。

github actions でサイトマップのURLを定期的に叩いて、刺激してみることにした。

github.com

ついでに、periodical の月日が更新されたらサイトマップ登録を追加するように自動化した。

暗号化キーを使うと、公開プロジェクトでも、個人IDが必要なジョブをまわせるので便利ですね。

bitwardenを使うと銀行のログイン・フォームを自動入力することができる。

銀行のログインフォームは自動入力が使えない

日本の銀行は、「自動入力」をさせないために、あれこれギルティな技を駆使してくる。

現代において自動入力は「正義」である、自動入力が危険なのは過去の話だ。

昔は入力履歴を共有PCで使ってしまったり、ブラウザ自動保存のパスワードが狙われたりしたからだが、現代において、スマホの入力画面を他人と共有することはまずありえない。

bitwarden で銀行のログインフォームの自動入力

これは、緑の銀行の一つでログインフォームを自動入力している例である。

ID入力を自動入力する方法

Bitwardenでは、フォームの「name」を指定すると、自動入力をすることができる。

bitwarden での設定

bitwarden で、カスタムフィールドを選ぶ

カスタムフィールドで、「テキスト」を選ぶ

テキストの「名前」と「値」を設定する。

name 名前の指定方法

Chromeの開発ツールで、自動入力したフォームを選び、input[name] を探す。

緑の銀行の場合、name="userId1" でした。

value / 値の指定

値の指定は、入力したい入力値をここに保存する。

複雑な入力フォームでの自動入力

自動入力をすることで「安全」にパスワードを使うことができる。

"安全"とは、自動入力のおかげで「十分に長い」「サイトごとに異なる」パスワードを使えるからだ。

自パスワードが十分に安全になる。この点において自動入力は素晴らしいので、ぜひ使ってほしい。

2FAとは、安全でないパスワードを防ぐのが最初の目的である。長いパスワードの自動入力があれば2FAがなくても相当安全である。

自動入力を呼びだす為に2FAを仕掛けておくのが理想状態であるとおもう

パスワードが古いとか言ってGPS監視アプリに誘導する会社だったり、自社アプリをインストールさせるためのポジション・トークだったりする。

他にも単に「新しいもの使ってる俺SUGEE」だったり。「パスワードは古い」などの言説は十分に注意して見ておくべきです。

ログイン状態を保存を自動でチェック

ログインフォームの「チェックボックス」などで、ログイン状態の保存の機能、このチェックをボックスを自動でチェックすることができる。

カスタムフィールドで「チェック」を選ぶと入力することができる。

その他、面倒な入力

その他の面倒な入力(秘密の質問)や、誕生日なども事前設定しておけば、瞬間に入力できる。

自動入力を拒否するのを拒否する。

どことは明言しませんが、自動入力を「拒否」するために、ダミーのインプットを設けるようなサイトでも対応が可能です。(いくつかの銀行にあります。

public dns で使えるDNSサーバー

public DNS で使えるDNSサーバー

公開DNSで、任意のISPから使えるDNSサーバーの一覧

Adguardのヘルプに記載があった→ https://kb.adguard.com/en/general/dns-providers

DoH / DoT

DNS over HTTPS / DNS over TLS も同様に記載がある。

ipv6

ipv6 でも使える

スクレイピングしておいた

AdguardのWEBサイトを、スクレイピングして、ipアドレスの一覧と、ドメイン名の一覧にしておいた。

https://github.com/takuya/public_dns_list

ネットワーク設定で内部のDNSを強制させ、外部DNSを使わないようにするためにこの一覧をフィルタに突っ込んでおけば、家庭内のAdguard Homeを強制させることができますね。

ubuntu で 一般ユーザ(非root)でsnap docker を使えるようにする

snap 版 docker をインストールした場合

sudo snap install docker 

docker グループがない。

docker グループがないために、一般ユーザでdocker コマンドができない。

## できる
sudo docker ps 
## できない
docker ps 

自分で作る

 sudo addgroup --system docker
 sudo adduser $USER docker
 newgrp docker
 sudo snap disable docker
 sudo snap enable docker

自分で作るしか無いです

公式ドキュメントに書いてありました。

https://snapcraft.io/docker

snapcraft 版の場合の注意。

わたし場合、systemctl をrestart しても動きませんでした。マウントの権限がおかしいようでした。

sudo adduser $USER docker
exit # id / group 反映
# ssh 
# 
sudo systemctl restart snap.docker.dockerd.service # だめだった
docker ps # 失敗
## 再起動が必要でした
sudo reboot 

再起動後は使えました。

takuya@raspi-ubuntu:~$ sudo docker ps
[sudo] password for takuya:
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
takuya@raspi-ubuntu:~$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
takuya@raspi-ubuntu:~$

たぶん、snapcraft の内部idマッピングのマウントが原因だと思う。

nextcloud で incompatible encoding になるのを何とかする。

エンコーディング警告が頻出する

nextccloudで ファイルをスキャンすると、エンコーディングのえらーがよく出る

will not be accessible due to incompatible encoding 

一番多かった原因

macOSutf-8 mac / nfd の濁点・半濁点の取り扱いが一番多かったエラーだった

対応

カレントディレクトリの中身をすべて nfc に統一する。

変換されるファイルのプレビュー

convmv -r -f utf8 --nfd -t utf8 --nfc * 

--notest をつけたら、実際に変換される

次のコマンドはすべて変換になる。 戻せないので注意。

convmv -r -f utf8 --nfd -t utf8 --nfc * --notest

OPNSenseのAPIでファイアウォールのAliasを更新する。API利用例

OPNSense設定を更新したいのでAPIを利用する

OPNSenseの設定を更新しようと思うと、APIを使うのが手っ取り早い。

APIJSONでGET/POSTができる。APIで設定を取得したり、更新したりができる。

https://docs.opnsense.org/development/api/core/firewall.htmlAPIの一覧がある

APIの使い方の調べ方

APIは、管理画面で使わている。だからドキュメント以外にも管理画面のリクエストを凝視すれば、使い方がわかる。

管理画面のAPIリクエストの例

f:id:takuya_1st:20220401143130p:plain

API を叩く準備:キー発行

APIを叩くには、キーを発行する。

キーは、「システム:→アクセス→ ユーザ→API 鍵→(+)ボタン」を押す。

(+)ボタンを押すと、キーがダウンロードされるので、それを変数に入れて使う。

キー発行は、ログインでもできる。ログインURLをcURLで叩いて、ワンタイムキーを取得する方法も取れる。ただパスワードをソース記載するのも面倒だしAPI鍵管理機能を使うのが楽だと思う。

API リクエスト例:ダッシュボード

管理画面のダッシュボードにある情報を取得する例

key=XXXXXXXXXXXXXXXbVt0mM8IEUv
secret=XXXXXXXXXXXXXX162pKmFQ
/usr/bin/curl --silent \
  --basic \
  --user "$key:$secret" \
  --insecure \
  https://192.168.1.1/api/diagnostics/activity/getActivity \
| jq .headers

cURLでリクエストを送信し、結果をJSONで受け取る。

JSONで受け取るので、jq と組み合わせて欲しいデータを取る。

APIリクエスト例:ファイアウォールエイリアス

OPNSenseの目玉機能である、ファイアウォールの「エイリアス」機能にアクセスしてみる。

key=XXXXXXXXXXXXXXXbVt0mM8IEUv
secret=XXXXXXXXXXXXXX162pKmFQ
curl \
  --basic \
  --user "$key:$secret" \
  --insecure \
  --verbose \
  https://192.168.1.1/api/firewall/alias/get  \
> out.json
cat out.json | jq .

エイリアスの一覧で、すべての情報を取得することができる

jq による整形

データは非常に多いので、jq でいい感じにフィルタ掛けてあげる

cat out.json | jq '.alias.aliases.alias | to_entries[] |  select( .value.name | test("my-alias-name") ) '

OPNSenseのレスポンスは、無駄のないきれいなJSONになっている。綺麗すぎてjq で処理しづらいので、 to_entries[] を使って変換する

to_entries[] を使う

to_entries[] を使うと、{ "uuid_a" { entry } } を ` { key:'uuid_a', value: { entry } } に変換できる

to_entries[] する前

{
   "id_1" : {
       age: 100
    }
   "id_2" : {
       age: 99
    }
}

to_entries[] を通した後

[
  {  key:"id_1",  value: {  age:100 } ,
  {  key:"id_2",  value: {  age:99 } ,
]

となる。

意図的に冗長なJSONに書き換えて、jqフィルタ処理が行いやすくできる。

jq 使ってJSONを整形したりフィルタする時の必須テクである。

API リクエスト POST 例:ファイアウォールエイリアス更新

ファイアウォールエイリアスにPOSTして更新する。

curl 'https://192.168.1.1/api/firewall/alias/setItem/1234567asdfghj' \
  -H 'content-type: application/json' \
  --data-raw '{"alias":{"enabled":"1",(中略)ent":""}' \
  --compressed \
  --insecure

POSTするデータは、管理画面のリクエストを見たほうが速い。

なのでcurl コマンドをChromeから取得 f:id:takuya_1st:20220401144939p:plain

実際にリクエストを作成するポイント

実際にリクエストを作成するとき、JSONをPOSTする。

一般的にJSONのPOSTをする場合、次のようになる。

curl http:///xxxxx  \
  -X POST
  -H 'content-type: application/json' \
  --data-raw '{"alias": ...... '

json を1行にまとめる。

curl--data-raw に使えるように、JSONを1行にまとめる。

JSONは改行をしてこそ人間が見やすい形式になる。しかし、プログラムで扱うには、改行が邪魔である。

jq -cjson を1行にまとめる。
cat req-data.json | jq -c . 

ここまでをまとめる。

ここまで調べたことをまとめて、OPNSenseのファイアウォールのAliisを更新するAPIコールを書いてみる。

function ip_list_to_content(){
  IPs=$1;
  IPs=$( echo $IPs | sed 's|\s|\\n|g' ) 
  echo $IPs
}
function build_firewall_alias_json(){
  name=$1
  body=$2
  description=$3
  JSON="
  {
    'alias':{
      'enabled':'1',
      'name':'${name}',
      'type':'network',
      'proto':'',
      'updatefreq':'',
      'content': '${body}',
      'interface':'',
      'counters':'0',
      'description':'${description}',
      'network_content':''
    }
  }"
  echo $JSON | sed -r "s|'|\"|g"
  
}
function json_req_param(){
  JSON=$1
  echo $JSON | jq -c . 
}
function post_to_opnsense(){
  URL=$1
  curl \
    --silent \
    --basic \
    --user "$key:$secret" \
    --insecure \
    -X POST \
    --data "${body}" \
    -H "Content-Type: application/json" \
    $URL
}
function get_to_opnsense(){
  
  URL=$1
  curl \
    --silent \
    --basic \
    --user "$key:$secret" \
    --insecure \
    $URL
}
function getItem_Of_Fw_Alias(){
  name=$1
  filter=".alias.aliases.alias | to_entries[] |  select( .value.name | test(\"${name}\") ) "
  URL="https://${OPNSenseAddr}/api/firewall/alias/get"
  get_to_opnsense $URL| jq -r "${filter}"
}
function get_UUID_by_name(){
  name=$1
  getItem_Of_Fw_Alias $name | jq -r .key
}

function google_smtp_ips(){
  for i in $( dig txt  _spf.google.com +short | \grep -Po '(?<=include:)[^\s]+' ); do
    dig $i +short  txt  | \grep -Po '(?<=ip4:)[0-9\./]+';
  done | uniq | sort -n
}
function update_fw_alias_google_smtp(){
  desc="GoogleのSMTPサーバー(spfから取得)"
  name="Google_SMTP"
  uuid=$( get_UUID_by_name $name )
  ip_list=$(google_smtp_ips)
  content=$( ip_list_to_content "${ip_list}" )
  json=$( build_firewall_alias_json $name $content $desc )
  body=$( json_req_param "$json" ) 
  URL="https://${OPNSenseAddr}/api/firewall/alias/setItem/${uuid}"
  ret=$(post_to_opnsense $URL $body )
  echo $name
  echo $ret | jq . 
}

function update_fw_alias_cloudflare_ipv4(){
  desc="Cloudflare ip list"
  name="Cloudflare"
  uuid=$( get_UUID_by_name $name )
  ip_list=$( curl -s https://www.cloudflare.com/ips-v4 )
  content=$( ip_list_to_content "${ip_list}" )
  json=$( build_firewall_alias_json $name $content $desc )
  body=$( json_req_param "$json" ) 
  URL="https://${OPNSenseAddr}/api/firewall/alias/setItem/${uuid}"
  ret=$(post_to_opnsense $URL $body )
  echo $name
  echo $ret | jq .
}

function main(){
  key=zzzzz/0mM8IEUv....
  secret=.....Aj4AC3+3EC5...
  OPNSenseAddr=192.168.1.1
  ## 
  update_fw_alias_google_smtp;
  ## 
  update_fw_alias_cloudflare_ipv4;
}



main;

openssl で証明書の署名リクエストを作成(証明書更新も同様)

openssl で証明書の署名リクエストを作成する。

証明書の、更新時も基本的には同じです。更新時も新規でリクエスと作成する。

CSR の作成

csr の作成時は、秘密鍵を指定して既存の秘密鍵を再利用できます。

更新・新規リクエス

既存の秘密鍵ファイルを利用して、CSRを作成する。

openssl req -key server.key -new > csr.pem

既存の秘密鍵ファイルを使うと更新時のリクエストにも利用できます

秘密鍵を新規作成してリクエスト作成

秘密鍵生成

秘密鍵を作成すると、既存ファイルが上書きされるので不便です。以下のコマンドは新規作成時だけに限るのがいいともいます。

openssl req -new -newkey rsa:2048 -nodes -keyout key.new.pem -out csr.pem

-newkeyを使うと、新規で秘密鍵が作られます。既存ファイルは上書きされるので、ファイル名に注意してください。

秘密鍵だけを作成する

秘密鍵だけを作成するのであれば、次のようになります。

openssl genrsa 2024 > server.key

秘密鍵を「パスワード」で保護する。

秘密鍵パスフレーズで保護することもできます。

openssl rsa -des3 -in server.key

openssl コマンドで証明書・秘密鍵・証明書リクエストのペアの一致を調べる。

openssl コマンドで秘密鍵・証明書の公開鍵一致を調べる

秘密鍵と証明書(公開鍵)のペアの枚数が増えてきて、どれが有効な秘密鍵かわからなくなった。

SSL証明書・署名リクエスト・秘密鍵から、modulusを取り出し、ハッシュ値の一致を調べれば、keyとCertの一致を調べられる。

Modulus とは、秘密鍵と公開鍵の積です。

公開鍵と秘密鍵の積(詳しくはRSA暗号を知る)

bashスクリプトRSA 鍵と x509証明書が正しいペアになっているかチェックする

CERT=../certs/example.com/fullchain.pem  
PKEY=../certs/example.com/privkey.pem
if [[ `openssl x509 -noout -modulus -in $CERT   | md5sum` ==  `openssl rsa -noout -modulus -in $PKEY |md5sum` ]] ;then
   echo OK
else
  echo NG
fi

もう少しコピペしやすく

CERT=../certs/example.com/fullchain.pem  
PKEY=../certs/example.com/privkey.pem
[[ `openssl x509 -noout -modulus -in $CERT   | md5sum`  \
   ==  `openssl rsa -noout -modulus -in $PKEY |md5sum` ]] \
  && echo OK.  its pair. || echo not pair

2つのコマンドで、modulusを知り、md5sum を求めて、その一致を見ている。

秘密鍵からmd5を計算

秘密鍵から導出し、ハッシュ値を計算

openssl rsa -noout -modulus -in secret.key | md5sum 

証明書から取り出しmd5を計算

証明書には、公開鍵と所有者情報とCAの署名が含まれる。そこから計算します。

openssl x509 -noout -modulus -in my-cert.pem | md5sum 

署名リクエストから取り出し md5を計算

署名リクエストは、公開鍵と所有者情報とダイジェストが含まれるので、そこから計算します。

openssl req -noout -modulus -in req.pem | md5sum 

ハッシュ値を比較すれば、わかる。

ハッシュ値の一致をみれば、同一の秘密鍵と公開鍵のペアで作成された証明書であるとわかる。

openssl x509 -noout -modulus -in unknown.pem | md5sum 
openssl rsa -noout -modulus -in secret.key | md5sum 

証明書の鍵ファイルがわからなくなったとか、多すぎて分かりづらいときに、チェックすることができ、ファイル名に惑わされず確信が持てる。

md5sum コマンドがない場合

md5sum コマンドの代わりに openssl md5 でもいい。

openssl が何度も登場して読みづらくなるので、本文中ではmd5sumに統一してある。

フォルダ内の鍵ファイルのmd5をサクッと求める例

鍵ファイルが増えてくると管理が大変なので、鍵ファイルのmodulus のmd5を事前に求めておくと、チェックがしやすい。

for i in $(find -type f -name '*key*' ) ; do
   printf "%-60s %s\n" $i $(openssl rsa -noout -modulus -in $i | md5sum | cut -d ' '  -f 1  );
done

curl コマンドでプロキシ設定をする。解除する

http プロキシで通信監視は、まだまだあります。

HTTPSが普及し尽くしたいまプロキシを入れるメリットはあまりないと思うのですが。

いまでも、念の為にプロキシを入れることは日常です。

apt / yum / dnf などでプロキシ設定しないとだめだったり、プロキシ設定をすると、ローカルホストに通信できなかったり不便

プロキシが不便になる場合。

プロキシ環境下で作業をしていると、ときどきやらかします。

export HTTP_PROXY=http://192.168.100.1/
### 作業
apt install nginx 
## チェック
curl 127.0.0.1 -H 'Host example.com '

curl はプロキシを使うのですが、localhost や自身のポートにプロキシが有効になっていて、うっかりやらかします。

ファイアウォール設定でローカルポートを未開放だとか気づかずに通信できずはまり込むことになります。

curl 使うときだけプロキシする

bash などにプロキシ設定を入れずに、特定コマンドだけでプロキシするほうがマシ。

export HTTP_PROXY=http://192.168.100.1/
### 全体プロキシしない
unset  HTTP_PROXY
### 作業
apt install nginx 
## チェック
curl 127.0.0.1 -H 'Host example.com '
curl --proxy=http://192.168.100/ t.co

サーバーの設定作業なら、プロキシするときとしないときを明示的に分けられるほうがいい。

curl 使うときだけ、プロキシをカット。

curl を使うときだけプロキシをカット。

export HTTP_PROXY=http://192.168.100.1/
### 作業
apt install nginx 
## チェック
curl  --noproxy '*' 127.0.0.1 -H 'Host example.com '

特定のサーバーだけプロキシをカットする

nopropxy は、ドメイン名を取れるので、特定のサーバーだけプロキシを使わせずに、通信確認ができる。

curl --noproxy 't.co'

プロキシ

プロキシはとても便利に使われると思いますが、

通信監視のメリットより、プライバシー漏洩後の訴訟リスクが大きすぎて、今の時代には合わないと思うんだけどなぁ。

サーバーを配置してる空間であればメリットはあるかもしれないが、それらもコンテナ技術で隠蔽しているし。

プロキシによりサーバー乗っ取りとマルウエア通信を未然に防止するというわりに、古いバージョンのOSやライブラリを使ってたりする企業が多く、見ていて悲しい。

https がエラーになって "\x16\x03\x01\x02" になる場合

httpsを設定したら、次のようにエラーになった。

nginx やApacheHTTPSを設定したら、エラーになった。再起動はうまくいく

"\x16\x03\x01\x02" というリクエストが解釈できないエラー。

==> access_log <==
192.168.11.1 - - [25/Mar/2022:18:26:23 +0900] "\x16\x03\x01\x02" 400 226 "-" "-"
192.168.11.1 - - [25/Mar/2022:18:28:30 +0900] "\x16\x03\x01\x02" 400 226 "-" "-"
192.168.11.1 - - [25/Mar/2022:18:28:34 +0900] "\x16\x03\x01\x02" 400 226 "-" "-"
192.168.11.1 - - [25/Mar/2022:18:28:39 +0900] "\x16\x03\x01\x02" 400 226 "-" "-"

ブラウザ上ではProtcol mismatchなど

ブラウザ上ではプロトコル・ミスマッチや、SSLエラーがでている。

原因

サーバーが、443 ポートでHTTPSをリッスンしていない。443ポートでHTTPをリッスンしている。

原因としては、HTTPサーバーが、443 ポートでHTTP通信しているために、openssl のセッションスタートのパケットが文字列処理されて、ファイルが見つからないなどのエラーになる。

"\x16\x03\x01\x02"は、SSL/TLS通信のネゴシエーション開始である。

httpdHTTPSではなく、HTTPとして解釈しようとして、"\x16\x03\x01\x02"という命令がHTTPに存在しないので、エラーになる。

要は、httpd の設定が甘い。SSL/TLSの関係を見直す。

対策。

HTTPSをちゃんと設定する。

SSLの証明書

証明書と鍵をちゃんと設定する。

秘密鍵ファイルが間違ってると起動し無いはずですが。再度確認しましょう。

ポートとHTTPS設定を見直す

ちゃんと https / 443 でリッスンしていますか

nginx の設定のリッスンと、httpに注意する。

server {

  server_name  example.com;
  listen 443 ssl http2 ;
  if ($scheme = http) {
    return 301 https://$server_name$request_uri;
  }
}

この設定ファイルはミスを誘発しやすいので、http→httpsリダイレクトは、設定を分ける。

Apache 2.4.8 以降で中間証明書を使ってませんか

Apache2.4.8 で SSLCertificateChainFile を使ってませんか。

SSLCertificateChainFileは deprecated です

apache では SSLCertificateChainFile は使わなくなりました。

中間証明書を末尾に追加します。

cat cert.pem chain.pem > fullchain.pem

docker-composeでプロジェクト名をいい感じに設定する。Found orphan containers 対策

docker-compose にはプロジェクト名称がある

おまえらのdocker-composeの使い方では、プロジェクト名称でハマる。

よくある使い方

cd my-docker
docker-compose up -d 

この場合、 プロジェクト名=フォルダ名になる。プロジェクト名は自動的に作られ、プロジェクト名を元に「ネットワーク名が作られる」

問題になる場面

同名フォルダ名で、ymlがあると面倒になる。けっこうこれは起きてしまう。 複数起動したらどうなるか

cd dirA/my-docker
docker-compose up -d 
#
cd another-project/my-docker
docker-compose up -d 

このとき、名前の重複が発生し、意図しない終了と削除が発生する。2つ目のディレクトリで、docker-compose downをしても で1つ目が終了してしまうなどが起きる。

無事に終了ができたとしてもネットワーク名の重複でFound orphan containers になる。

要は、 docker-compose.yml は単純に2つ起動できないのである。

問題が起きる原因。

なぜそうなるか。プロジェクト名が同じになり、ネットワーク名がおなじになり、同じネットワークを使うプロジェクトで名前被りが発生して面倒が起きる。

プロジェクト名を指定しろ。

docker-composeを複数起動するのなら、ちゃんとプロジェクト名を付ける必要がある。

cd dirA/my-docker
docker-compose -p MyProj up -d 

プロジェクト名を管理しろ

ただし、プロジェクト名称がわからなくなると docker-composeコマンドが使えない

おなじpsコマンドでも得られる結果は全く違ったものになる。

cd dirA/my-docker
docker-compose -p MyProj  ps 
docker-compose ps 
  • -p があるときは、プロジェクト名称を参照
  • なしの場合。「プロジェクト名=ディレクトリ名=my-docker」が使われる

プロジェクト独立空間

docker-compose はプロジェクト単位で全く別の独立空間になってる。

docker コンテナ自体が独立空間であり、名前をつけられるのと同じ。docker-composeはプロジェクト名毎で独立空間になっている。

未設定時は、プロジェクト名称=フォルダ名なのである。意図しない名前重複が発生し理由がわからず頭を抱えることになる。

プロジェクト名をいい感じに指定する。

プロジェクト名称をどこかに、設定するべきである。プロジェクト名称を決めずに利用し名前重複を未然に防止する必要がある。

また、プロジェクト名を手軽に参照できるようにする必要がある。

方法1 環境変数を使う

COMPOSE_PROJECT_NAMEを使うと、 -p NAME を省略できる。

cd dirA/my-docker
export COMPOSE_PROJECT_NAME=MyProj
docker-compose  ps 

次の使い方もできる。

cd dirA/my-docker
COMPOSE_PROJECT_NAME=MyProj docker-compose   ps 

ただし、順番に注意する。

docker-compose -p name ps # 動く
docker-compose ps -p name # 動かない。

-p は 一番先頭に付けないと動きません。

方法2 .env ファイルを使う。

dirA/my-docker/.env を使うことで、プロジェクト名称を省略できる。

cd dirA/my-docker
echo 'COMPOSE_PROJECT_NAME=MyProj' > .env
docker-compose  ps 

.env ファイルは、gitプロジェクトとは別に実行時に指定するために使えるものであるが、なぜかプロジェクトにも使われる。

.env ファイルが使える理由

docker-composeには、--env-file のオプションがあり、 --env-fileのデフォルトが、.env になっている。 docker-composeはカレントディレクトリからファイルを読み込むので、./.env が対象になる。

そのため、.env を設置すれば読み込まれる。

.env は docker-compose.yml中に変数や依存を放り込むために使われる。

docker-composeのコマンドとymlの変数を混ぜるので、管理がしにくいところである。

プロジェクト名を意識する

docker-composeを使うとき、暗黙プロジェクト名に注意を払うか、明示的プロジェクト名に変える必要がある。

それをしないと、名前空間がかぶり、コンテナ名・ネットワーク名で重複し起動終了に予想外の自体が起きる。

プロジェクト名をソースコードで指定しといてくれないか。

env ファイルにプロジェクト名を書いたとしても。プロジェクト名は常に意識しておくべきである。

#.env ファイルが有る場合
docker-compose ps 
# .env ファイルがない場合
docker-compose ps 

コマンドが同じでもプロジェクト名 が違うと全く別の空間に docker-composeされるのである。

だから、docker-composeを使うならプロジェクト名をちゃんと書いておけ。

systemdの場合

systemd で docker-composeするとき

[Unit]
Description=docker-composeの%iコンテナ管理
Requires=docker.service
After=docker.service

[Service]

## プロジェクト名称をつける
Environment=COMPOSE_PROJECT_NAME=MyXXX
WorkingDirectory=/var/project
ExecStart=/usr/bin/docker-compose up

[Install]
WantedBy=multi-user.target

ちゃんとソースコードや設定ファイルに明示するようにdocker-composeしてほしいのである。

でないと、まとめて複数起動したときにハマるのである。CI/CDとかでも起きるのである。

sudo -u runner docker-compose up
sudo -u runner docker-compose up

適当にソース渡されて適当にテストしたら思いきりドハマリしたじゃないか。

docker は人類の手に負えない。人間が触るもんじゃない。k8s や portainerなど自動管理するためのものだ。

-p は 一番先頭に付けないと動きません。とか意図しない動作もあるし。docker-composeは両手をあげて初心者に使わせるものじゃないと思うんだ。

docker-composeは思わぬところでハマりますよね。

--profile--project とかさ。もうちょっと何とかならないのかなぁ

curl でDNS上書き。/etc/hosts書き換えずにhttps 接続(証明書)を確認する。curl だけで resolve

サーバーの移転時にHTTPSの証明書を確認したい

毎回毎回、/etc/hostsを書き換えると不便極まりないので、代替手段はないか調べた。

openssl には servername オプションがあるのでcurlでもサーバー名を解決するオプションがないか調べたら。あった。

curl だけで hostsファイル代替手段がある。resolve

curl には resolve オプションがあり、ドメイン名とIPアドレスの名前解決を上書きできる。

curl   --resolve example.com:192.168.100.2 http://example.com

resolve オプション便利ですね。

https の場合

httpsの場合は、次のように 443 をつければ、hostsファイルの代わりに使える。

curl   --resolve example.com:443:192.168.100.2 https://example.com

証明書の移動ができたかcurlでチェックできる

ブラウザで見なくても、HTTPSの確認ができる。

openssl

また、証明書のチェックは、opensslだけでもできる

openssl s_client --connect 192.168.194.145:443 | openssl x509 -noout -text

openssl を使う場合、証明書チェックが走るので Can't use SSL_get_servername が出てしまうが、接続して証明書を取ることはできる。

サーバー名SNI相当のものを指定する場合.servernameを指定する。

openssl s_client --connect 192.168.2.147:443 --servername example.com  | openssl x509 -noout -text

ALPNに対応している通信なら

openssl s_client --connect 192.168.2.147:443 -alpn h2 --servername  example.tld < /dev/null

関連資料

SSL証明書の有効期限やSANをopensslコマンドで調べる(https証明書確認) - それマグで!

SSL証明書の有効期限やSANをopensslコマンドで調べる(https証明書確認)

証明書の有効期限を調べる。

openssl コマンドでサクッと証明書の期限を調べる。

枚数が多くなり、またcertbotのような管理ソフトがない、CA発行証明書の有効期限をまとめて調べたい。

20枚もあるといちいち、ブラウザに突っ込んで調べるのは面倒くさい

openssl で証明書の期限を見る

openssl x509 -noout -enddate -in /path/to/xxx.cert

openssl で証明書の詳細を見る。

期限以外の詳細を確認する。

openssl x509 -noout -text  -in /path/to/xxx.cert

SAN / subjectAltName を確認する

openssl x509 -noout -ext subjectAltName  -in /path/to/xxx.cert

CN / subject commonName を確認する

openssl x509 -noout -subject  -in /path/to/xxx.cert

SN / serial Number (シリアル)を確認する。

openssl x509 -noout -serial -in /path/to/xxx.cert

サーバー証明書を直接確認する。

openssl s_client -connect example.com:443 < /dev/null 2> /dev/null |\
  openssl x509 -noout -enddate | \

openssl s_client で接続して、証明書取得し、有効期限を確認する。

スクリプトにまとめる。

#!/usr/bin/env
domain="example.tld"

openssl s_client -connect $domain:443 < /dev/null 2> /dev/null |\
  openssl x509 -noout -enddate | \
  sed 's/notAfter=//' | \
  xargs -i date -d {} +"%F"

日付形式をdate でフォーマットして、サクッと証明書の有効期限を見る。

SSL/TLSの証明書期限切れをチェックするように、自動スクリプトに仕込んで、通知と併せて使うといい。

check_expires example.tld && mailto takuya 'example.tld will expire.'

改訂

  • 2023-02-18 OpenSSLコマンドのオプションを修正。SAN・CNの取得方法も追加

systemd のユニットを@引数で再利用する。

systemd のユニットファイルを引数で使いまわしする

一部が違うだけのユニットファイルを、引数で使い分ける。テンプレートを作成できる。

systemctl start my-service@foo.service
systemctl start my-service@bar.service

引数は %i で受け取ります。

i はインスタンス名の意味です。@name.service はインスタンスという名称です。

作り方。

引数を受け取るユニットファイルを作成する。

my-service@.service

my-service@.service のように@.service で名前を定義する

引数の受け取り方。%i

%i で引数を受け取る。

[Unit]
Description=テンプレートなサービスを作成する練習。 %i 秒スリープします

[Service]
ExecStart=bash -c 'while : ; do echo loop ; sleep %i ;done '

[Install]
WantedBy=default.target

テンプレートを有効にする。

パラメタを受け取る、ユニットを登録します。

cp my-service@.service /etc/systemd/system
systemctl daemon-reload

引数を加えてサービスにします。

systemctl start my-service@foo.service 
## または
systemctl enable my-service@foo.service 

enable すると再起動後も有効になる。

%i 以外の変数

%i のインスタンス名称以外の「変数」は最初から使えるものも多いです

公式サイトに変数の一覧が公開されています。

関連資料

systemd で引数で分割を使う(@:アットマーク)ユニットのテンプレート化で似たような複数サービスをまとめる。 - それマグで!

参考資料

https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers

macosでFileVault暗号化利用時の、リモート再起動不可とID/PWでのログインができない問題

macOSのfileVaultで暗号化しているとき、再起動が変わる。

macOSでFileVault(ディスクの暗号化)を設定しているとき、ログイン画面が変わる。

ログイン画面が変わるのは、「ログイン前に暗号化の解除」が入るため。

f:id:takuya_1st:20220325032809p:plain

FileVaultが有効になっている例

暗号化の解除が入るのだがこれが問題。

暗号化の解除が入るので、従来のログイン処理に前処理が挟まる。

このログインの前処理が、FileVaultなしの従来の機能と整合性が取れないために問題が発生する

問題点1:再起動できない(reboot不可)

sudo reboot 

これで再起動できないんですよ。メニュから再起動をしなくてはいけない。

また、sudo reboot をしても暗号化の解除ができないので「電源オフになる」

リモートSSH経由の再起動で詰む

つまり、「常時起動のmacbookSSHでリモートから管理」していたり、mac mini をサーバー(VNCサーバー)として使ってると停電時に、二度とログインできなくなるぞ

解決策 reboot コマンドの代用品を使う。

reboot でシステムを再起動せず

sudo fdesetup authrestart

reboot コマンドの代わりに、再起動前に情報を保存する、ログイン認証を済ませた上で再起動する

FileVault を有効にしたら reboot を 次のようにalias かけておく必要がありそうだ。

alias reboot='fdesetup authrestart'

fdesetup はFileVault関連のユーティリティと設定コマンドである。コマンドじゃなくて設定パネルで使わせてよ。

問題点2 ログイン画面のユーザー一覧を消せない

FileVault有効時にログインの問題

ログイン画面ではユーザー一覧を非表示にすることが出来るが、「暗号化の解除に表示されるユーザーは、ID/PWにできない」んですよ。

設定では、ID/PWでログインを設定しても→無駄

f:id:takuya_1st:20220325031704p:plain

ログイン画面は「絶対にユーザアイコン選択画面」

FileVaultを利用すると暗号化の解除が入るのだけど、ユーザーでログインする必要がある。そのログイン画面が、「ユーザーアイコン」を選ぶ画面しか無い。

macOSの「設定」の「ユーザー」の「ログインオプション」はあっさり無視される。

問題点 予備ユーザーやアカウントを複数作ってると邪魔で仕方ない。

メインのユーザとサブユーザーで、用途別にユーザを切り替えて使えっているときは不便で仕方がない。いちいち選択するのすらわずわらしい。

解決策

ログイン画面からユーザーを隠す

https://www.maketecheasier.com/hide-user-accounts-from-macos-login-screen/

FileVaultといいCatallinaといい・・・

ログイン画面のユーザーアイコン強制とかダサいんでやめてほしいんですよね。

再起動時にSSHでリモートアンロックできないのもやめてほしいですよね。

Appleはベースになるところの管理はちゃんとしてると思ってたけど、どうなってんですかねぇ。

利用者に何も情報を出してくれないのは流石にないわ。

ID/PWじゃなくてユーザーアイコンが出るので設定を10回くらい確認したわ。

FileVaultって本当に必要?

FileVaultを未処理の場合でも、SSDを取り外しされてデータが盗まれることはない。macSSD換装困難でムカつくけど、安全だ。

MacにUSBドライブで別のOSで起動されてもユーザーの領域はある程度保護される。TouchBar後のmacは別OSで起動時にユーザログインが必要(T2機能)*1

SSH秘密鍵はKeychains内蔵のssh-agent機能で保護される。

パスワード類はキーチェーンや1password/bitwarden のようなソフトウェアで保護される。

メール類はもはやGmailだろう。

となると、FileVaultオフでデータが流出するとしたらどこからだ。

Evernoteのようなローカルに個人ファイルを持ってるものだろう。

となると、ローカルにデータがなければ安全である。iCloudドライブやFUSEを使ってしまえば、もはやFileVaultすら必要ない。

そう考えると、AppleがFileVaultよりiCloudドライブを一押ししてるのも頷ける。

ここまで考えて気づくのだが、いまのMacbookにFileVaultって本当に必要なんでしょうか。

*1: Appleによると次のとおりである。

MacApple T2チップが搭載されている場合は、起動ディスクを変更するために、追加のセキュリティ機能を設定する必要がある場合があります。起動セキュリティユーティリティとは?を参照してください。 https://support.apple.com/ja-jp/guide/mac-help/mchlp1034/mac