- 投稿日:2019-08-21T23:04:50+09:00
Ubuntu18.04LTS ユーザー登録のミス
社内メンバーをユーザー登録する際、
useradd hogihogiで登録した結果、
\home
配下にhogihogiのディレクトリができなかった。
正しくはadduser hogihogiで
\home\hogihogi
を作成してくれる。
ごっちゃになっちゃうのでメモしときます。
ちなみにグループ追加はadduser hogihogi groupで作成。ちゃんとできたか確認は
id -a hogihogiで確認。useraddコマンド間違えて使っちゃった場合は
userdel -r hogihogiで消してみる。プロセスIDが動いてて消せなかった場合は
kill -KILL processIDで消してから
adduser --force-badname hogihogiでユーザーを再追加できる。
どれもどこかに書いてあることばかりだけど、備忘録として書き残します。。。
- 投稿日:2019-08-21T22:46:25+09:00
vagrantの時間のずれを修正する方法
vagrantの時間のずれの修正方法
勤怠管理アプリを作ってみようかなーと思っていたところ、ゲストとホストの時間がずれていて気持ち悪かったので修正しました。
この投稿が同じことで困っている誰かの解決の一助になれば幸いです。時間がずれている方で以下のコマンドを実行しました。
$ date -s "2019/08/21 22:21:00"
すると
date: 日時を設定できません:
許可されていない操作です
と出ました。sudoを頭につけて実行
$ sudo date -s "2019/08/21 22:21:00"
そうすると
2019年 8月 21日 水曜日 22:21:20 JST
と時刻が反映されました。
他の方法
自分は他の方法がうまくいかずにこの方法にたどり着きましたが以下も参考にしてみてください。
https://polidog.jp/2014/01/08/vagrant/
http://hiroki-prog.hatenablog.com/entry/2018/07/15/135539
最後に
いろんな方法がありましたが試してみてエラーや不具合が発生するたびにエラー文などを検索してみると徐々に解決に近づくとおもいます。
この記事に誤り、改善点などございましたら編集リクエストやコメントにてご指摘をお願いいたします。
- 投稿日:2019-08-21T21:28:02+09:00
Dockerを使ってみよう-1
この記事は
Dockerを分かった気になれるDockerのコンセプトとかあまり紹介しないまま、脳死コピペでなんとかいける仕様になってます。今回はDockerをインストールし、コンテナを作って起動させるところまで書きます。
次回はAWSのECRにコンテナをプッシュする作業について書きたいと思います。仕事でDockerを使えって言われたけど、どこから手を付ければいいのか分からなかった数日前の自分のために…
環境
・Amazon Linux AMI 2018.03.0 (HVM)
・Docker CE
・ポート4000Dockerをインストール
最初からスーパーユーザーになってたら楽かもしれませんね。
アプデsudo yum updateインストールsudo yum install docker -yDocker起動sudo service docker startDocker Imageを作成
ここでは
Dockerfile
、requirements.txt
、app.py
のファイルを三種類を作り、編集していきます
以下のコードはDocker公式のドキュメントから拝借しています。リンクは記事の一番下にあるのでぜひ見に行ってくださいね!
コードの詳細が書かかれてますよ(英語)ファイルを作成
touch Dockerfile内容はこれに編集します
Dockerfile# Use an official Python runtime as a parent image FROM python:2.7-slim # Set the working directory to /app WORKDIR/app # Copy the current directory contents into the container at /app COPY. /app # Install any needed packages specified in requirements.txt RUN pip install --trusted-hostpypi.python.org -rrequirements.txt # Make port 80 available to the world outside this container EXPOSE80 # Define environment variable ENVNAME World # Run app.pywhen the container launches CMD["python", "app.py"]
requirements.txt
も作り、編集していきますrequirements.txtFlask Redis
app.py
も同様ですapp.pyfrom flask import Flask from redis import Redis,RedisError import os import socket # Connect to Redis redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2) app=Flask(__name__) @app.route("/") def hello(): try: visits = redis.incr("counter") except RedisError: visits = "<i>cannot connect to Redis, counter disabled</i>" html = "<h3>Hello {name}!</h3>"\ "<b>Hostname:</b> {hostname}<br/>"\ "<b>Visits:</b{visits}" return html.format(name=os.getenv("NAME","world"), hostname = socket.gethostname(), visits=visits) if__name__=="__main__": app.run(host='0.0.0.0',port=80)Dockerを走らせます
いよいよですよ…
まずはビルドから
friendlyhelloのタグをつけてやりますので、タグの名前を変更しても大丈夫です
docker build -t friendlyhello .Docker imagesでビルドを確認します
docker images先ほどつけた名前がREPOSITORYの下にでますので、ちゃんとありましたら走らせます!!!!
ポート4000を使うのでEC2インスタンスの方でもちゃんと開けておいてくださいねdocker run -p 4000:80 friendlyhelloアウトプットに'#Running on http://0.0.0.0.80/ (Press CTRL+C to quit)' がでましたら、インスタンスのPublic IP アドレスとポート番号を指定して実際にHello World!が表示されてるか確認しにいきましょう
簡単にいうとこんな感じです↓
http://your_public_ip:4000/参考にしたサイト
この記事で使用したコードはDocker公式のご提供です
・https://docs.docker.com/get-started/part2/アマゾンさんは日本語に対応していますので
・https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html
- 投稿日:2019-08-21T20:34:53+09:00
メール送信のパスワードが破られたらどうなるか
序章
あるところに、世界に公開している メールサーバA がありました。
このサーバで aaaa@xxxx.yyy(仮称)というメールアドレスを、
登録/運用していました。この aaaa@xxxx.yyy には送信用パスワードが設定されていましたが、
ある日、何者かによって、パスワードが ばれてしまいました。
(おそらくパスワードの総当たり攻撃で、偶然 判明したのでしょう。)このパスワードを引き当てた相手(ファースト スパマー)は、
正規のアドレス aaaa@xxxx.yyy から、世界中にスパムメールを送りつけたのです。それだけではありません。
ファーストスパマーは、親切にも他のスパマー仲間に
メアドとパスワードを教えてあげたのです(たぶんですが。)その結果 世界中から、メールサーバA の送信用の
25番ポート(587番や465番も)にアクセスが集中したのです。対応開始
メールサーバA が どうもおかしいということで、さっそく調査しました。
数時間かけてようやく、上記の現象を把握しました。まずはスパムメールを止めないといけません。
:
どうやって?
:メールサーバA では postfix を利用していて、postfix の停止を考えましたが、
それだと aaaa@xxxx.yyy 以外のアカウントも使えなくなってしまうので、
この案は却下しました。とりあえず aaaa@xxxx.yyy のパスワードを変えてみました。
長いパスワードに変えてやりましたよ。これで大丈夫、と netstat コマンドで確認すると・・・
スパマーからの接続は まだ残っています。なぜ?おそらく、新規の接続はできなくなったけど、
パスワード変更前のコネクションが、切断されずに残っているのでしょう。それではと、これらコネクションを iptables コマンドで切断してみました。
IPアドレスごとに切断するので、何個ものコマンドを根気強く投入しました。
少し時間は かかりましたが、残っていたコネクションはすべて、
消えて無くなりました。これでOK! とその日は家に帰りました。
翌日・・・
はぁぁっ!?
スパムメール送信は、まだ続いていました。パスワードが再度ばれた? のではありません。
じつは送信キューに、大量の処理待ちが残っていたのです。スパマーは昨日のコネクション接続時に、
これでもか!と送信要求をしていたのでしょう。
そのため1日経った時点でも、まだ数万のキューが残っていました。業を煮やした私は、最終手段をとります。
「キュー全削除じゃぁっ!」参考URL
Postfixのメールキューを確認、削除する方法最後に
これでようやく、ほんとにスパムメール送信が収まりました。
スパムメールの受信も厄介ですが、送信のほうは さらに厄介です。
なにせ加害者になってしまいますからね。ほんと気を付けましょう。(まぁスパムメールの大半は、宛先不明で届かなかったようですが。)
ちなみに破られたパスワードは、文字数も短く「弱い」パスワードだったようです。
今後はアカウント作成時、「強い」パスワードを要求するように設定変更しました。
- 投稿日:2019-08-21T18:59:43+09:00
Oracleリスナーログのローテーション(linux版)
リスナーログのローテーション
日々溜まっていき、自動でローテーションしてくれず、そのうち爆発するリスナーログのローテーション方法です。
シェルで下記のように記載
#!/usr/bin/bash #■リスナーログを別ファイルとする。 lsnrctl set log_file /u01/app/oracle/diag/tnslsnr/hogehoge/listener/trace/listener1.log #■次にファイルを移動。 mv /u01/app/oracle/diag/tnslsnr/hogehoge/listener/trace/listener.log /var/ora/lsnrlog/listener_`date "+%Y%m%d_%H%M%S"`.log #■元のリスナーログに戻す。 lsnrctl set log_file /u01/app/oracle/diag/tnslsnr/hogehoge/listener/trace/listener.log #■ファイルを削除。 rm /u01/app/oracle/diag/tnslsnr/hogehoge/listener/trace/listener1.logvarlogにバックアップしてますが、たまに削除したほうがいいです。
これをcronに登録しておけばバッチリ!
ユーザはOracleユーザで行うことを忘れずに。
- 投稿日:2019-08-21T14:41:43+09:00
Linuxでファイルシステムを削除する
あるディスクの先頭1MBをふっとばします。
dd if=/dev/zero of=/dev/xvdf bs=1M count=1
- 投稿日:2019-08-21T14:35:59+09:00
Google Edge TPUとは何ですか?
Edge TPUとは何ですか?
Edge TPUは、低電力デバイス向けの高性能ML推論を提供するGoogleが設計した小さなASICです。 たとえば、MobileNet V2などの最先端のモバイルビジョンモデルを400 FPSで電力効率の高い方法で実行できます。
Edge TPUビルトインを含む複数の製品を提供しています。
Edge TPUはどの機械学習フレームワークをサポートしていますか?
TensorFlow Liteのみ。
Edge TPUはどのタイプのニューラルネットワークをサポートしていますか?
第一世代のEdge TPUは、畳み込みニューラルネットワーク(CNN)などのディープフィードフォワードニューラルネットワーク(DFF)を実行できるため、さまざまな視覚ベースのMLアプリケーションに最適です。
サポートされているモデルアーキテクチャの詳細については、モデルの要件を参照してください。
Edge TPUのTensorFlow Liteモデルを作成するにはどうすればよいですか?
モデルをTensorFlow Liteに変換する必要があり、量子化に対応したトレーニング(推奨)またはトレーニング後の完全整数量子化のいずれかを使用して量子化する必要があります。 次に、Edge TPUとの互換性のためにモデルをコンパイルする必要があります。 詳細については、Edge TPUのTensorFlowモデルをご覧ください。
ただし、画像分類アプリケーションを構築している場合は、Cloud AutoML Visionを使用して、Edge TPUと互換性のあるモデルを簡単に構築することもできます。 このWebベースのツールは、独自の画像を使用してモデルをトレーニングし、モデルを最適化してからEdge TPUにエクスポートするためのグラフィカルUIを提供します。
Edge TPUの処理能力はどのくらいですか?
Edge TPUは、1秒あたり4兆回の操作(テラ操作)(TOPS)を実行でき、各TOPSに0.5ワット(1ワットあたり2 TOPS)を使用します。
実際にどのようなパフォーマンスを提供しますか?
こちらのベンチマークをご覧ください。(https://coral.withgoogle.com/docs/edgetpu/benchmarks)
Edge TPUは加速MLトレーニングを実行できますか?
はい、ただし最終層のみを再トレーニングします。 TensorFlowモデルはEdge TPUで高速化するためにコンパイルする必要があるため、後ですべてのレイヤーの重みを更新することはできません。 ただし、2つの異なる方法で高速転送学習を実行するAPIを提供しています。
クロスエントロピー損失関数を使用して、最終的に完全に接続されたレイヤーだけの重みを更新する逆伝播。
新しいデータからの画像埋め込みを使用して最終層に新しい活性化ベクトルを刷り込む重み刷り込み。これにより、非常に小さな小さなデータセットで新しい分類を学習できます。Dev BoardとUSB Acceleratorの違いは何ですか?
Coral Dev Boardは、SOMに統合されたSOCとEdge TPUを含むシングルボードコンピューターであるため、完全なシステムです。 SOMを削除(または個別に購入)し、3つのボード間コネクタを介して他のハードウェアと統合することもできます。このシナリオでも、SOMにはSOCとEdge TPUを備えた完全なシステムとすべてのシステムインターフェイスが含まれます( I2C、MIPI-CSI / DSI、SPIなど)は、基板間コネクタの300ピンを介してアクセスできます。
一方、Coral USB Acceleratorは、既存のシステムにコプロセッサーとしてEdge TPUを追加するアクセサリーデバイスです。USBケーブルを使用してLinuxベースのシステムに接続するだけです(最高のパフォーマンスを得るにはUSB 3.0をお勧めします)。
Edge TPUチップだけを購入できますか?
いいえ、現在、スタンドアロンのEdge TPU ASICは提供していませんが、USB 3.0またはPCI-Eインターフェイスのいずれかを使用して、既存のハードウェアシステムのコプロセッサーとしてEdge TPUを簡単に統合できる2つの製品を提供しています。
しかし、あなたはここからサンゴ装置を購入することができます:https://store.gravitylink.com/global
- 投稿日:2019-08-21T13:25:17+09:00
実運用を想定したLinuxユーザ管理の例
概要
実運用を想定して、Linux系のOSへのユーザをこんな感じで管理、運用したらよいのではないかという案です。
実際はケースバイケースなのでこれをもとに個々の要件などと照らし合わせて細部の設定を変更していくイメージで書いています。ユーザとグループについて
- 各サーバーへのSSH接続は個人毎のアカウントを作成して公開鍵認証方式のみとする。
- 個人アカウントのパスワードは設定するが、主な目的はsudoコマンド実行時に聞かれるパスワードであり、パスワード認証によるSSH接続は禁止する
- 個人ユーザの所属グループは開発者:
developers
or 運用者:maintainers
の2パターンとする- システム管理者のみwheelグループをサブグループとして追加する
- グループをまとめると以下の通り。
- developers:ベンダーなどの開発担当者が所属するグループでログなどの参照のみを可能と想定したグループ
- maintainers:運用担当者の所属するグループでapplicationsグループに所属するユーザにスイッチができる。
- applications:ミドルウェアやアプリケーション(Web系/バッチ系)の実行ユーザの所属グループ。自作アプリの場合は主グループ。ミドルウェアでインストール時に独自にユーザやグループを作るタイプ(apache/nginx/mysql/plsql等)場合はサブグループでも可。ポイントとしてはmaintainersグループの所属のアカウントからこのグループに所属するユーザにsu可能とする点。(これが必ずしもベダーではないので、細かいことはサーバーの用途毎にやるべきだと考える)
- wheel:Redhat系におけるsudoでrootコマンドを実行できるようにするグループ(管理者権限オプションが指定されたユーザのサブグループに指定する)
- adm:journalctlでログを参照できるようにするためのグループで全員所属させる方針とする。
参考
方針としてだれでもすべてのログを参照することは許容してしまっているが、特定のログしか見せないようにするにはこのグループに全員所属させるわけではなく、個別の参照できるjournalログを制御する設定が必要になるので、sudo設定のjournalctlのオプション付き設定のコマンドエリアスなどを定義するのかな?その他事前準備
- SSH接続からsudoで
useradd
,usermod
,userdel
がパスワード無し(:NOPASSWORD)で実行できること管理される側のサーバーの事前準備
PAMによるsuコマンドの実行を制限する
- wheelグループ以外のスイッチは原則禁止
- 例外としてmaintainersグループに所属するユーザはapplicationsグループの所属ユーザにスイッチできる。
/etc/pam.d/su#%PAM-1.0 # rootは全部OK(デフォルト) auth sufficient pam_rootok.so # 現在のユーザ(スイッチ前)の所属グループがmaintainersの場合は1行スキップする auth [success=1 ignore=1 default=ignore] pam_wheel.so use_uid group=maintainers # 現在のユーザ(スイッチ前)の所属グループがwheel以外の場合はスイッチ不可のチェック(maintainersグループはここは通らない) auth required pam_wheel.so use_uid # 現在のユーザ(スイッチ前)の所属グループがmaintainers以外の場合はスイッチ不可 auth [success=1 default=ignore] pam_succeed_if.so use_uid user notingroup maintainers # maintainersグループもapplicationsグループのユーザにしかスイッチできない auth required pam_succeed_if.so user ingroup applications # 以下はデフォルト設定の(はず) auth substack system-auth auth include postlogin account sufficient pam_succeed_if.so uid = 0 use_uid quiet account include system-auth password include system-auth session include system-auth session include postlogin session optional pam_xauth.so備忘録
デフォルト定義から
auth required pam_wheel.so use_uid
のコメントを外すだけだと、wheelグループ以外のスイッチができなくなってしまう。末尾に"root_only"とすればrootのみのチェックとなるが、逆にrootユーザ以外のスイッチが自由になってします。
→よって、以下のようにpam_wheel.soモジュールの判定をスキップできる条件をpam_succeed_if.soモジュールで行う。sudoの設定例
デフォルトでwheelグループはパスワードありでの任意のsudoが実行可能であり、
visudo
などで/etc/sudoersを直接編集する箇所はなかった(はず)なので、/etc/sudoers.d/配下に任意のファイル名で以下の内容のファイルを作成する
ポイントは以下の通り。
- developers/maintainersグループともにsudoでファイルの中身を参照するコマンドなどで/var/log配下のファイルを参照できる
↑のadmグループでも記載したが、すべてのログを見せたくない場合は個別に限定するなどの設定が必要だが、この投稿はあくまもで一例であり、実際にはサーバーの用途毎に設定を変更すべきかもしれない。。。- DBサーバーの設定例として、maintainersグループのユーザはsudoでDBサーバーの再起動(
systemctl restart mysql.service
etc.)が実行できる。 他の用途のサーバーであれば、適宜このあたりを可変にするとよいと考える。/etc/sudoers.d/hogehogeCmnd_Alias LOG_LIST = /usr/bin/ls /var/log/*, /usr/bin/ls * /var/log/* Cmnd_Alias LOG_VIEW = /usr/bin/cat /var/log/*, /usr/bin/cat * /var/log/*, \ /usr/bin/head /var/log/*, /usr/bin/head * /var/log/*, \ /usr/bin/tail /var/log/*, /usr/bin/tail * /var/log/*, \ /usr/bin/more /var/log/*, /usr/bin/more * /var/log/*, \ /usr/bin/less /var/log/*, /usr/bin/less * /var/log/*, \ /usr/bin/grep /var/log/*, /usr/bin/grep * /var/log/*, \ /usr/bin/egrep /var/log/*, /usr/bin/egrep * /var/log/* Cmnd_Alias DB_MAINTAINANCE_COMMAND = /usr/bin/mysql*, /usr/bin/systemctl * mariadb, /usr/bin/systemctl * mariadb.service %developers ALL=(ALL) LOG_LIST, LOG_VIEW %maintainers ALL=(ALL) LOG_LIST, LOG_VIEW, DB_MAINTAINANCE_COMMAND注意事項してこのファイルのパーミッション設定が必要。
chmod 0440 /etc/sudoers.d/hogehoge
ユーザ管理用シェルの実装例
ユーザ作成
実行例)
cat /dev/urandom | tr -dc '[:alnum:]' | head -c8 | useradd.sh -a -g maintainers -c "User Name" "userid" "$(cat ~/.ssh/id_rsa.pub)"
注意事項:公開鍵文字列には空白を含むため、ダブルクォートなどで囲まないとエラーになります。
useradd.sh#!/bin/bash #==================================================== # SSH接続用の個人アカウントを作成するシェル # root or パスなしでsudoできるユーザでの実行すること #==================================================== # usagesに表示する名前です。ここではシェルのファイル名にしています。 PROGRA_NAME="$( basename $0 )" # 共通関数のロード . $(dirname $0)/user_common.sh # ヘルプ表示。(オプションの指定方法に不正があった場合にも出力) function _usage() { cat << __EOF__ Usage: ${PROGRA_NAME} [-g|--group developers|maintainers] [-a|--admin] [-c|--comment usercomment] [-h|--help] usrename public_key. And input the password used by \`sudo\` from the standard input. Description: Create a personal account for SSH connection. Options: -c --comment Uesr comments.(=useradd command "c" options.) -g --group Specify the user's group. "developers" or "maintainers". default is "developers". -a --admin Add use to wheel group.(Not specify is false) -h --help Show help message. __EOF__ } # オプション値の初期値をここで定義する。 COMMENT="" MAIN_GROUP=developers IS_ADMIN=false # bashの組み込み関数`getopts`はlong nameオプションに対応してないので以下のように引数すべてループしてオプションを解析します。 while [ $# -gt 0 ]; do # 現在位置の引数からオプションの名前を抽出(先頭のハイフン1回or2回繰り返しは除去) OPT_NAME=$(echo $1 | sed 's/^-\{1,2\}//') case "${OPT_NAME}" in # ユーザコメントオプション 'c' | 'comment' ) COMMENT=$2 shift 2 ;; # グループ指定オプション 'g' | 'group' ) MAIN_GROUP=$2 shift 2 ;; # wheelグループに所属させるオプション 'a' | 'admin' ) IS_ADMIN=true shift 1 ;; 'h' | 'help' ) # ヘルプメッセージを表示して即終了。 _usage exit 0 ;; * ) # ハイフンで始まる場合は不正なオプションとする。(ただし、引数自体をハイフンで始める値が受け付けられない問題があるけど) if [[ "$1" =~ ^- ]]; then output_error "${PROGRA_NAME}: illegal option -- '${OPT_NAME}'" _usage exit 1 fi break ;; esac done # パスワードは標準入力から read -sp "Creating user's password: " USER_PASSWORD # 対話型実行の場合は改行されない対策 tty -s && echo "" #---------------------------------------------------------------- # チェック #---------------------------------------------------------------- # コマンド(シェル)自体のオプションを除く必須パラメータはユーザ名と公開鍵(文字列)の2つ if [ $# -ne 2 ]; then output_error "Required username & public key(string)!!" _usage exit 1 fi USER_NAME=$1 PUBLIC_KEY=$2 # ユーザの書式と存在チェック _check_user "${USER_NAME}" || exit 1 # 公開鍵書式チェック _check_publickey "${PUBLIC_KEY}" || exit 1 # パスワードの書式チェック _check_password "${USER_PASSWORD}" || exit 1 # グループ指定された文字列チェック _check_group "${MAIN_GROUP}" || exit 1 # ログ参照でjournalctlコマンドを実行できるようにサブグループにadmを指定する SUBGROUPS="-G adm" # rootへのスイッチが可能なオプションが指定された場合 if ${IS_ADMIN}; then # 管理者は運用担当者のグループでなければならない(事実上、このチェックがなくても弊害はないが紛らわしいので) if [ "${MAIN_GROUP}" != "maintainers" ]; then output_error "Administorator is must be maintainers group." exit 1 fi # wheelグループへも追加する SUBGROUPS=" wheel" fi #---------------------------------------------------------------- # ユーザ作成&パスワード設定&公開鍵のデプロイ #---------------------------------------------------------------- # "--password"オプションだとなんでかうまく設定されなかったで以下で回避 sudo useradd -g ${MAIN_GROUP} ${SUBGROUPS} -ms /bin/bash -c "${COMMENT}" "${USER_NAME}" sudo sh -c "echo ${USER_NAME}:${USER_PASSWORD} | chpasswd" # 公開鍵のデプロイ sudo mkdir -p /home/${USER_NAME}/.ssh sudo chmod 0700 /home/${USER_NAME}/.ssh sudo sh -c "echo ${PUBLIC_KEY} > /home/${USER_NAME}/.ssh/authorized_keys" sudo chmod 0600 /home/${USER_NAME}/.ssh/authorized_keys sudo chown -R "${USER_NAME}:${MAIN_GROUP}" /home/${USER_NAME}/.ssh # 結果出力 output_info "Created user: $(id ${USER_NAME}) / $(egrep "^${USER_NAME}:.+$" /etc/passwd)" exit 0ユーザ更新
ユーザ更新は更新したい要素のみをオプション指定します。(パスワードは標準入力からリード)
実行例)
cat /dev/urandom | tr -dc '[:alnum:]' | head -c8 | usermod.sh ―p -r -g developers -c "User Name" -k "$(cat ~/.ssh/id_rsa.pub)" "userid"
usermod.sh#!/bin/bash #==================================================== # SSH接続用の個人アカウントを更新するシェル # root or パスなしでsudoできるユーザでの実行すること #==================================================== # usagesに表示する名前です。ここではシェルのファイル名にしています。 PROGRA_NAME="$( basename $0 )" # 共通関数のロード . $(dirname $0)/user_common.sh # ヘルプ表示。(オプションの指定方法に不正があった場合にも出力) function _usage() { cat << __EOF__ Usage: ${PROGRA_NAME} [-k|--publickey ssh's public_keys(authorized_keys)] [-g|--group developers|maintainers] [-p|--password] [-a|--admin] [-c|--comment usercomment] [-h|--help] usrename. And input the password used by \`sudo\` from the standard input. Description: Update a personal account for SSH connection. Options: Specify only the fields to be changed. -c --comment Uesr comments.(=useradd command "c" options.) -k --publickey Update ssh authorized_keys. -g --group Specify the user's group. "developers" or "maintainers". -p --password Update user password(the password used by \`sudo\`). Password input from standard input. -a --admin Add use to wheel group.(Not specify is false) -r --revoke-admin Add use to wheel group.(Not specify is false) -h --help Show help message. Examples: Update authrized_keys. => ${PROGRA_NAME} -k "ssh-rsa AAAAA...........== foo@hostname" foo __EOF__ } # オプション値の初期値をここで定義する。 IS_ADMIN=false IS_REVOKE_ADMIN=false # bashの組み込み関数`getopts`はlong nameオプションに対応してないので以下のように引数すべてループしてオプションを解析します。 while [ $# -gt 0 ]; do # 現在位置の引数からオプションの名前を抽出(先頭のハイフン1回or2回繰り返しは除去) OPT_NAME=$(echo $1 | sed 's/^-\{1,2\}//') case "${OPT_NAME}" in # ユーザコメントオプション 'c' | 'comment' ) COMMENT=$2 shift 2 ;; # "-k" or "--publickey"の場合(正確には"--k"や"-publickey"も許容するけど。。。) 'k' | 'publickey' ) # "-k" or "--publickey"の次の引数をオプションの値として抜粋 PUBLIC_KEY=$2 # 公開鍵妥当性チェック _check_publickey ${PUBLIC_KEY} || exit 1 # "-g" or "--group"とその値の分引数配列をシフトさせる。 shift 2 ;; # "-g" or "--group"の場合(正確には"--o"や"-optvalue"も許容するけど。。。) 'g' | 'group' ) # "-g" or "--group"の次の引数をオプションの値として抜粋 MAIN_GROUP=$2 # developers or maintainers以外はNG _check_group "${MAIN_GROUP}" || exit 1 # "-g" or "--group"とその値の分引数配列をシフトさせる。 shift 2 ;; # パスワードの更新 'p' | 'password' ) # パスワードの入力自体は標準入力から受ける read -sp "Updating user's password: " USER_PASSWORD # 対話型実行の場合は改行されない対策 tty -s && echo "" _check_password ${USER_PASSWORD} || exit 1 shift 1 ;; # wheelグループにも追加する場合 'a' | 'admin' ) IS_ADMIN=true shift 1 ;; # wheelグループを削除する場合 'r' | 'revoke-admin' ) IS_REVOKE_ADMIN=true shift 1 ;; 'h' | 'help' ) # ヘルプメッセージを表示して即終了。 _usage exit 0 ;; * ) # ハイフンで始まる場合は不正なオプションとする。(ただし、引数自体をハイフンで始める値が受け付けられない問題があるけど) if [[ "$1" =~ ^- ]]; then output_error "${PROGRA_NAME}: illegal option -- '${OPT_NAME}'" _usage exit 1 fi break ;; esac done #---------------------------------------------------------------- # チェック #---------------------------------------------------------------- # コマンド(シェル)自体のオプションを除く必須パラメータはユーザ名と公開鍵(文字列)の2つ if [ $# -ne 1 ]; then output_error "Required username!!" _usage exit 1 fi USER_NAME=$1 # 存在チェック&所属グループが個人ユーザの所属するグループのユーザであるか? _check_exists_user "${USER_NAME}" || exit 1 # 変更後の主グループ判定 if [ -n ${MAIN_GROUP} ]; then CHANGED_MAIN_GROUP=${MAIN_GROUP} else CHANGED_MAIN_GROUP=$(id -gn "${USER_NAME}") fi # 変更後にwheelグループに所属させるか判定 CHANGED_ADMIN=false if ${IS_ADMIN}; then # adminの付与を解除オプションが同時に指定された場合 if ${IS_REVOKE_ADMIN}; then output_error "--admin option and --revoke-admin option cannot be specified at the same time." exit 1 fi CHANGED_ADMIN=true elif ! ${IS_REVOKE_ADMIN}; then for GRP in $(id -Gn ${USER_NAME}); do if [ "${GRP}" == "wheel" ]; then CHANGED_ADMIN=true break fi done fi # 管理者は運用担当者のグループでなければならない if ${CHANGED_ADMIN}; then if [ "${CHANGED_MAIN_GROUP}" != "maintainers" ]; then output_error "Administorator is must be maintainers group." exit 1 fi fi #---------------------------------------------------------------- # 更新処理 #---------------------------------------------------------------- # コメント更新オプションが指定された場合 if [ -n "${PUBLIC_KEY}" ]; then sudo usermod -c "${COMMENT}" "${USER_NAME}" fi # 公開鍵オプションが指定された場合 if [ -n "${PUBLIC_KEY}" ]; then # 作成時にこけて再実行することも考慮して作り直しておく sudo mkdir -p /home/${USER_NAME}/.ssh sudo chmod 0700 /home/${USER_NAME}/.ssh sudo sh -c "echo ${PUBLIC_KEY} > /home/${USER_NAME}/.ssh/authorized_keys" sudo chmod 0600 /home/${USER_NAME}/.ssh/authorized_keys sudo chown -R "${USER_NAME}:${MAIN_GROUP}" /home/${USER_NAME}/.ssh fi # パスワードが指定された場合 if [ -n "${USER_PASSWORD}" ]; then # パスワード更新 sudo sh -c "echo ${USER_NAME}:${USER_PASSWORD} | chpasswd" fi # 所属グループが指定された場合 if [ -n "${MAIN_GROUP}" ]; then sudo usermod -g ${MAIN_GROUP} "${USER_NAME}" fi # wheelグループへの追加 if ${IS_ADMIN}; then # 既に所属していてもエラーにはならないのでそのまま実行 sudo gpasswd -a "${USER_NAME}" wheel fi # wheelグループからの削除 if ${IS_REVOKE_ADMIN}; then # こちらは所属していないのに削除するとエラーになるので判定 for GRP in $(id -Gn ${USER_NAME}); do if [ "${GRP}" == "wheel" ]; then sudo gpasswd -d "${USER_NAME}" wheel > /dev/null break fi done # もともと所属していなくてもエラーにはしない fi # 結果出力 output_info "Updated user: $(id ${USER_NAME}) / $(egrep "^${USER_NAME}:.+$" /etc/passwd)" exit 0ユーザを削除
ユーザ削除のオプションは強制モードのみ。
実行例)
userdel.sh -f "userid"
userdel.sh#!/bin/bash #==================================================== # SSH接続用の個人アカウントを削除するシェル # root or パスなしでsudoできるユーザでの実行すること #==================================================== # usagesに表示する名前です。ここではシェルのファイル名にしています。 PROGRA_NAME="$( basename $0 )" # 共通関数のロード . $(dirname $0)/user_common.sh # ヘルプ表示。(オプションの指定方法に不正があった場合にも出力) function _usage() { cat << __EOF__ Usage: ${PROGRA_NAME} usrename. Description: Delete a personal account for SSH connection. Options: -f --force Ignore error when not exists user. -h --help Show help message. __EOF__ } # オプションの初期値定義 # 存在しない場合もエラーにしない(複数サーバー実行時に途中で落ちた場合などの対処用) IS_FORCE=false # bashの組み込み関数`getopts`はlong nameオプションに対応してないので以下のように引数すべてループしてオプションを解析します。 while [ $# -gt 0 ]; do # 現在位置の引数からオプションの名前を抽出(先頭のハイフン1回or2回繰り返しは除去) OPT_NAME=$(echo $1 | sed 's/^-\{1,2\}//') case "${OPT_NAME}" in 'f' | 'force' ) # 強制指定された場合は存在チェック関数でエラーがあっても"0"正常とする IS_FORCE=true shift 1 ;; 'h' | 'help' ) # ヘルプメッセージを表示して即終了。 _usage exit 0 ;; * ) # ハイフンで始まる場合は不正なオプションとする。(ただし、引数自体をハイフンで始める値が受け付けられない問題があるけど) if [[ "$1" =~ ^- ]]; then output_error "${PROGRA_NAME}: illegal option -- '${OPT_NAME}'" _usage exit 1 fi break ;; esac done #---------------------------------------------------------------- # チェック #---------------------------------------------------------------- # コマンド(シェル)自体のオプションを除く必須パラメータはユーザ名の1つ if [ $# -ne 1 ]; then output_error "Required username!!" _usage exit 1 fi USER_NAME=$1 # 存在チェック&所属グループが個人ユーザの所属するグループのユーザであるか? RESULT=$(_check_exists_user "${USER_NAME}" 2>&1) if [ $? -ne 0 ]; then if ${IS_FORCE}; then exit 0 fi output_error "${RESULT}" exit 1 fi #---------------------------------------------------------------- # ユーザを削除 #---------------------------------------------------------------- sudo userdel -r "${USER_NAME}" if [ $? -ne 0 ]; then exit 1 fi output_info "Deleted user: ${USER_NAME}" exit 0上の3つシェルの共通関数などの定義ファイル
user_common.sh#==================================================== # ユーザの作成、変更、削除で利用する共通関数定義 #==================================================== # 個人アカウントの所属しうるグループの定義 GROUP_VALID_VALUES="developers maintainers" # シアン色でメッセージを標準出力に赤字で出力するための関数。 function output_info() { echo -e "\e[36m$@\e[m" } # 黄色字で警告メッセージを標準出力に出力するための関数。 function output_warn() { echo -e "\e[33m$@\e[m" >&2 } # 赤字で標準エラー出力にメッセージを出力するための関数。 function output_error() { echo -e "\e[31m$@\e[m" >&2 } # ユーザ名チェック function _check_user() { local USER_NAME=$1 # 書式チェック # - 先頭は英小文字のみ # - 使用可能文字は英小文字/数字/ハイフン/アンダースコア/ドット # - 先頭は英小文字のみ # - 末尾は英小文字or数字 # - 3文字以上、30文字以下 local REGEXP_PTN='^[a-z]{1}[-.0-9_a-z]{1,28}[0-9a-z]{1}$' if [[ ! "${USER_NAME}" =~ ${REGEXP_PTN} ]]; then output_error "Invalid username: '${USER_NAME}'. Regexp pattern: ${REGEXP_PTN}" return 1 fi # 既に存在したらNG if id ${USER_NAME} > /dev/null 2>&1; then output_error "Already exists user: ${USER_NAME}." return 1 fi } # オプションで指定、または更新・削除時の既存ユーザのメイングループの妥当性をチェックする function _check_group_value() { local MAIN_GROUP=$1 for GRP in ${GROUP_VALID_VALUES}; do if [ "${MAIN_GROUP}" = "${GRP}" ] ; then return 0 fi done return 1 } # グループオプションのチェック function _check_group() { local MAIN_GROUP=$1 # 空文字でないこと、次のオプションではない(=ハイフンで始まらない)というチェック if [[ -z "${MAIN_GROUP}" ]] || [[ "${MAIN_GROUP}" =~ ^-+ ]]; then output_error "Group is empty value." return 1 fi if ! _check_group_value "${MAIN_GROUP}"; then output_error "${MAIN_GROUP} is invalid values. Allowd value is (${GROUP_VALID_VALUES})" return 1 fi return 0 } # 存在チェック&所属グループが個人ユーザの所属するグループのユーザであるか?(update/delete時) function _check_exists_user() { local USER_NAME=$1 # local ORIG_MAIN_GROUP=$(id -gn ${USER_NAME} 2>&1) # →なぜかlocalをつけるとexit statusが正しく取れないので宣言と分けて書く local MAIN_GROUP MAIN_GROUP=$(id -gn ${USER_NAME} 2>&1) if [ $? -ne 0 ]; then output_error "${MAIN_GROUP}" return 1 fi # 指定ユーザの所属グループの妥当性チェック if ! _check_group_value "${MAIN_GROUP}"; then output_error "${USER_NAME} does not belong to the target groups(${GROUP_VALID_VALUES})." return 1 fi return 0 } # sshの公開鍵の妥当性をチェックします function _check_publickey() { # ssh-keygenコマンドを使うのでいったんファイルに吐き出す local TMP_PUBLIC_KEY_FILE=/tmp/AUTHORIZED_KEYS_$$ echo $1 > ${TMP_PUBLIC_KEY_FILE} # 上の_check_exists_userと同じでなぜかlocalをつけるとexit statusが正しく取れないので宣言と分けて書く local RESULT RESULT=$(ssh-keygen -l -f ${TMP_PUBLIC_KEY_FILE} 2>&1) local RET=$? rm -f ${TMP_PUBLIC_KEY_FILE} if [ ${RET} -ne 0 ]; then output_error "${RESULT}" fi return ${RET} } # パスワードの妥当性をチェックします function _check_password() { PASSWORD=$1 # パスワードは8文字以上で英大文字・小文字・数字の1つ以上の組み合わせ if [[ ${#PASSWORD} -ge 8 && "${PASSWORD}" == *[A-Z]* && "${PASSWORD}" == *[a-z]* && "${PASSWORD}" == *[0-9]* ]]; then return 0 else output_error "Password must be at least 8 characters, And must be contain at least one of uppercase letters, lowercase letters and numbers." return 1 fi }実運用時の想定したフロー
- 各個人ユーザは秘密鍵と公開鍵のペアを作成する
ssh-keygen -t rsa -b 4096 -N '秘密鍵のパスフレーズ' -C 'コメント' -f 出力する秘密鍵のファイルパス
- 管理者にアカウント作成を依頼する
- ユーザID(3文字以上。30文字いない。英小文字、数字、ドット、ハイフン、アンダースコアのみ。先頭の文字は英子文字のみで末尾に記号は不可。)
- ユーザ名(任意。なくてもよい)
- 公開鍵(1のコマンド実行後に秘密鍵のファイル名.pubで出力されるファイル)
- 運用者か開発者か? ※所属グループとかシステム管理者にするかは管理側のグループでジャッジ?
- 管理者は各サーバーの↑のシェルをSSH経由で実行する。
- 1台ずつやると大変なので以下のようなシェルを作っておくとよいと考える。
- パスワードは申請者から申請してもらってもよいが、以下の例では作成時に全サーバー同じになるようにしているので、ここで生成されたパスワードを申請者に連絡する想定です。(ほんとは発行されたパスワードをメールとチャットツール系などで伝達するのが理想だが。。。)
# パスワード生成 function _generate_password() { # cat /dev/urandom | tr -dc '!#$%&-@;:=~+0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' | head -c8; echo "" # 上だとすべての文字種に組み合わせにできないのでちょっと乱暴だが、文字種毎の利用数を固定にする L_CHARS=$(cat /dev/urandom | tr -dc '[:lower:]' | head -c3) # 英小文字3 U_CHARS=$(cat /dev/urandom | tr -dc '[:upper:]' | head -c3) # 英大文字3 N_CHARS=$(( RANDOM % 10 )) # 数字1 S_CHARS=$(cat /dev/urandom | tr -dc '!#$%&' | head -c1) # 記号1 # 結合した文字列をfoldで1文字ずつ分解(改行)して、並び順をシャッフルして最後に改行を除去する echo "${L_CHARS}${U_CHARS}${N_CHARS}${S_CHARS}" | fold -w1 | shuf | tr -d '\n' return 0 } USER_PASSWORD=$(_generate_password) echo ${USER_PASSWORD} TARGET_HOSTS="guest1,guest2,guest3" for TARGET in "guest1,guest2,guest3"; do ssh ${TARGET} "echo \"${USER_PASSWORD}\" | useradd.sh -a -c \"ユーザ名\" -g \"maintainers\" \"ユーザID\" \"$(cat 申請された公開鍵のパス)\"" done※↑のTARGET_HOSTSに記載した文字列は、
~/.ssh/cofig
に定義した接続定義名を想定。この接続ユーザは接続先ホストにおいてsudoでuseradd/usermod/usedelが実行可能なユーザである。~/.ssh/configHost guest1 HostName ホスト名 or IPアドレス User sudoでuseradd/usermod/usedelが実行可能なユーザ Port 22 UserKnownHostsFile ~/.ssh/known_hosts StrictHostKeyChecking no PasswordAuthentication no IdentityFile 秘密鍵のパス IdentitiesOnly yes Host guest2 HostName ホスト名 or IPアドレス User sudoでuseradd/usermod/usedelが実行可能なユーザ Port 22 UserKnownHostsFile ~/.ssh/known_hosts StrictHostKeyChecking no PasswordAuthentication no IdentityFile 秘密鍵のパス IdentitiesOnly yes Host guest3 HostName ホスト名 or IPアドレス User sudoでuseradd/usermod/usedelが実行可能なユーザ Port 22 UserKnownHostsFile ~/.ssh/known_hosts StrictHostKeyChecking no PasswordAuthentication no IdentityFile 秘密鍵のパス IdentitiesOnly yesその他、作成した担当者が離任したら、管理者が削除シェルを実行して削除する。
余談
上のようなシェルを作ったが、台数増えるといろいろ面倒なのでユーザ管理部分はLDAPサーバーを立てた方がよさそう。。。
- 投稿日:2019-08-21T12:30:52+09:00
指定したディレクトリ以下を検索する
- 投稿日:2019-08-21T09:59:19+09:00
Vi(Vim)の基本操作メモ
エンジニアが1年目には覚えたいViの基本操作について、個人的によく使う操作方法をメモします。
起動
$ vi ファイル名
入力モードについて
viはコマンドモードで立ち上がる (コマンドモードについて下記に記載)。
文字を入力する場合は、入力モードに移る以下キーを入力する。[a] ...カーソルの右から入力開始(a: Add の意味) [A] ...行末から入力開始 [i] ...カーソルの左から入力開始(i: Insert の意味) [I] ...行頭から入力開始 [o] ...現在の行の下に1行挿入し、その行頭から入力開始 [O] ...現在の行の上に1行挿入し、その行頭から入力開始コピー・貼り付けについて、入力モードでは何か他のテキストの文字列、外部サイトの文字列をコピーし、そのまま貼り付けることができる。
コマンドモードについて
escキーでコマンドモードに移る。ファイル・文字列操作、保存等が可能。
カーソル移動
1文字移動
基本的に矢印キーは使うなと昔上司に言われました。でも使ってもいいと思いますが…
左: [←キー] or [h] or [BackSpace] 右: [→キー] or [l] or [Space] 上: [↑キー] or [k] 下: [↓キー] or [j]単語ごとに移動
[w] ...1語次へ [b] ...1語前へ削除・貼り付け
[x] ...1文字削除。 [yy] ...1行コピーしクリップボードへ格納する。 [dd] ...1行切り取りしクリップボードへ格納する、または1行削除。 [p] ...クリップボードの内容をカーソル行の下の行に貼り付ける。行番号
:set number ...行番号を表示 :se nu ...行番号を表示(上に同じ) ::set nonumber :se nonu :行番号 ...行番号を指定して移動検索
[/]文字列 ...カーソルの後方に検索を行う [?]文字列 ...カーソルの前方に検索を行う [n]文字列 ...次の検索該当文字列へ [N]文字列 ...前の検索該当文字列へ置換
:s/文字列1/文字列2/ ...カーソル行で最初の「文字列1」のみを「文字列2」に置換する :s/文字列1/文字列2/g ...カーソル行の「文字列1」を全て「文字列2」に置換する取り消し
[u] ...直前の操作をやめる(u: Undo の意味) [U] ...行全体に操作を取りやめるビジュアルモード
ctrl + V でビジュアルモードに遷移。矩形選択しxで選択箇所の削除など可能。
終了処理
終了 :q …書込みを行わず終了(quitの意味) :q! ...書込みを行わず強制終了 :wq ...書込み後終了 :wq! ...書込み後強制終了色分けされていたほうが見やすいので、Vimを推奨されている方もいますが、
基本的な操作方法についてはViもVimも同じです。
- 投稿日:2019-08-21T08:27:44+09:00
RPMパッケージのインストールコマンド
(強制的な)RPMインストールのオプション(2018.03)
RPMパッケージの強制インストール
- すでにインストールされているパッケージを無視してインストールする
--replacepkgs
$ rpm -ihv --replacepkgs hoge-3.2-1.i386.rpm
- ファイルの重複を無視してインストールする
--replacefiles
$ rpm -ihv --replacefiles hoge-3.2-1.i386.rpm
- ダウングレードを許可しインストールする
--oldpackage
$ rpm -ihv --oldpackage hoge-3.2-1.i386.rpm
- 強制的にインストールする
--force
$ rpm -ihv --force hoge-3.2-1.i386.rpm
- 投稿日:2019-08-21T08:11:29+09:00
logrotateの備忘録
logrotateのメモ...(2018.01)
設定ファイル
共通の設定ファイル
/etc/logrotate.conf個別の設定
/etc/logrotate.d/****実行
動作確認(debugモードで実行)
# /usr/sbin/logrotate -dv /etc/logrotate.conf
-d, -debug : デバッグモード
-v, -verbose : 詳細表示モード通常実行
# /usr/sbin/logrotate /etc/logrotate.conf
強制実行(条件を満たしていなくてもログローテさせる)
# /usr/sbin/logrotate -f /etc/logrotate.conf
-f, -force : 強制実行
確認
- 実行結果確認
# cat /var/lib/logrotate/logrotate.status