RHEL8.6のGitLab-CEからRHEL9.4のGitLab-CEに移行する

前提

  • 移行元
    • RHEL 8.6
    • GitLab-CE 15.11.13
  • 移行先
    • RHEL 9.4
    • GitLab-CE 17.5.4

手順の流れ

  • 移行先にGitLabをインストールする
  • 移行元のGitLabをアップグレードし、移行先のGitLabと同じバージョンにする
  • 移行元のGitLabでバックアップを取得し、新サーバーに移行して取り込む

はじめに:GitLabバージョン選定について

GitLabのバージョンは何でもよい。支障が無ければ現時点で最新バージョンを選ぶとよい。(脆弱性が高い頻度で出ているため)

ただし、OSによってはGitLabのサポートバージョン外であり、例えば、RHEL9に対応した GitLab 15.11.13 のパッケージは存在せずインストールできない。 どのOSでインストールできるかは、以下から検索してRPMパッケージが存在するかで確認する。 packages.gitlab.com

また、今回の手順は、GitLabのバックアップ/リストアユーティリティを用いて移行するが、そのためには移行元・先のGitLabバージョンが完全一致している必要がある。

要するに移行元をアップグレードする必要があるが、アップグレードはいくつかのバージョンを経由しないといけないことがある。 現バージョンから目的のバージョンへアップグレードするのに必要な経由バージョンは、以下から確認できる。

gitlab-com.gitlab.io

ちなみに、今回の例は以下。長い。

https://gitlab-com.gitlab.io/support/toolbox/upgrade-path/?current=15.11.13&target=17.5.5&distro=centos&edition=ce

1.移行先にGitLabをインストールする

手順は割愛。そのうち書く。

2.移行元のGitLabをアップグレードする

移行元サーバーからインターネットにアクセスできる場合の手順

# 外部リポジトリの追加
sudo curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash

# 自動バックアップの抑制
sudo touch /etc/gitlab/skip-auto-backup

# GitLab Upgrade Path に従ったバージョンアップを繰り返していく。
sudo yum install gitlab-ce-16.3.9
sudo yum install gitlab-ce-16.7.10
sudo yum install gitlab-ce-16.11.10
sudo yum install gitlab-ce-17.1.8
sudo yum install gitlab-ce-17.3.7
sudo yum install gitlab-ce-17.5.4

# 設定の再構築を行う
sudo gitlab-ctl configure

移行元サーバーからインターネットに直接アクセスできないが、PCから自由にファイル転送できる場合の手順

# RPMファイルを移行元サーバーに配置する。今回は、/home/worker 以下に配置する前提。

# 自動バックアップの抑制
sudo touch /etc/gitlab/skip-auto-backup

# GitLab Upgrade Path に従ったバージョンアップを繰り返していく。
sudo yum localinstall /home/worker/gitlab-ce-16.3.9-ce.0.el8.x86_64.rpm
sudo yum localinstall /home/worker/gitlab-ce-16.7.10-ce.0.el8.x86_64.rpm
sudo yum localinstall /home/worker/gitlab-ce-16.11.10-ce.0.el8.x86_64.rpm
sudo yum localinstall /home/worker/gitlab-ce-17.1.8-ce.0.el8.x86_64.rpm
sudo yum localinstall /home/worker/gitlab-ce-17.3.7-ce.0.el8.x86_64.rpm
sudo yum localinstall /home/worker/gitlab-ce-17.5.4-ce.0.el8.x86_64.rpm

# 設定の再構築を行う
sudo gitlab-ctl configure

3.GitLabのバックアップを取得する

# 一部サービスの停止
sudo gitlab-ctl stop unicorn
sudo gitlab-ctl stop sidekiq

# そのほか、作業中に別ユーザーから操作されるのを防ぐため、先に制限を行っておく。
# ただし、GitLab本体は起動していないとバックアップができない。

# バックアップの作成
sudo gitlab-rake gitlab:backup:create

# バックアップファイルの確認
ls -l /var/opt/gitlab/backups


# 生成したバックアップファイルを作業用PCに取得しておく

4.バックアップを移行先GitLabに取り込む

# バックアップファイルを移行元サーバーに配置する。今回は、/home/worker 以下に配置する前提。

# バックアップの移動
sudo mv /home/worker/*_gitlab_backup.tar /var/opt/gitlab/backups/

# 一部サービスの停止
sudo gitlab-ctl stop unicorn
sudo gitlab-ctl stop sidekiq

# バックアップファイルのインストール
# このとき、BACKUPにはファイル名の取得日時~バージョン名 までを指定する
# 以下、1736559467_2025_01_11_17.5.4_gitlab_backup.tar を取り込む例。
sudo gitlab-rake gitlab:backup:restore BACKUP=1736559467_2025_01_11_17.5.4

# 一部サービスの再開
sudo gitlab-ctl start unicorn
sudo gitlab-ctl start sidekiq

# 設定の再構築を行う
sudo gitlab-ctl configure

大規模開発でGitLabを採用して新基盤移行後もGitLabを採用する話

大規模開発のGitリポジトリにGitLabを採用した話。CI基盤構築の参考になれば。

TL;DR

  • 大規模プロジェクトのソースコード管理/プルリクエスト管理のツールとしてGitLabを採用した。
  • 行基盤がクローズするので、クラウドの新基盤に移行した。
  • 移植性を重視したこと、5,6社が混在する大規模組織でクラウドサービスのアカウント管理をする体制がなかったことから、クラウドの各フルマネージドサービス(AWS CodeCommit / Azure DevOps / ECS / EKS など)の採用は見送った

身の上話

今、自分がベンダー側で参画している大規模プロジェクトでたまたまサーバー選定に意見できるようになり、ソースコード管理のツールとしてGitLab利用を提案した。 about.gitlab.com

というも、提案前は「ファイルシステムに直で置いたGitリポジトリSSHでアクセスする」原始的な運用をしており、1つの操作(メインブランチへの誤Commit/Push、ブランチ誤削除)で大問題が普通に起こるのに統制・権限制御が全く無かったのだ。開発に従事する人間がテスター・マネジメントを除いても100人超、関係会社5社を超えているなか、手心のある運用は崩壊するのが目に見えていた。

言葉の強弱はあるが、提案は以下のニュアンスだった気がする。

  • 今のソースコード管理では、マージの前後でミスが多発するうえトラッキングが難しいです。GitLabというツールを使って改善します。
  • 個別機能開発・不具合対応開始時に、特定の命名規則に従った個別ブランチとマージリクエスト(※GitLab版のプルリクエストの呼称)を作成して、今コミットしているソースコードは何なのか、Gitlabやブランチ見てわかるようにしてください。マージリクエスト使えば、ソースコードの差分のプレビューや後追いが簡単にできますよ。
  • 開発済みのソースコードを統合したメインブランチ(main、develop、各社開発済み資産ブランチ)への直接pushは制限として禁止します。各社開発済みのブランチをこちらで統合して、問題があれば連絡しますね。

浸透期間を要したものの、この目論見は成功したと思っている。

いくつか確信があり、その中の一つが、前運用時にやっていた「ソースコード開発差分を開発前・開発後でファイルのハードコピーをとって証跡としておく」プロセスの省略。

これが役に立つのであればよいが、最新ソースには色んなコミット入り乱れるから単純比較には使えず、リリース前の差分確認の参考になるにしても、配置ミスやバージョンが古くなるミスがあり信用できない(そもそもGit使ってやるべきだが、業界的に未習熟の人が管理・担当をやっていることがあるので、標準化や維持が難しい。歯がゆい)。結局、何か問題が起きた時に、当時何したのか?の責任追及以外に役に立たない。

そんな後ろ向きなエビデンス作りにミスや漏れに気を付けながら時間を割く必要があるのか?その思いは開発者、ひいてはチェックする側の人間も同様であり、GitLabのマージリクエスト作成時の差分プレビュー作成機能による自動化は強力な後押しになった。

構成と運用上の課題

GitLabは、仮想マシンを1台立ててRPMファイルをインストール。リバプロあり。ネットワークは閉域網のみ、インターネット公開無し。

  • サーバーの安定性は、まちまち。時々レスポンスが悪くなる。
  • 通常運用(ユーザー管理、マージリクエスト作成、ブランチ管理)の範囲では大きく不便はない。
  • ユーザーは、GitLab内に登録して管理。権限は、ブランチを直接メンテナンスする人間には「Owner」「Maintener」、一般開発者は「Developer」に割り当て。

また、マージリクエストの運用は、実際はRedmineの障害票チケットや別途変更管理票が親で、それのソースコード版という位置づけになっている。 一般的なプルリクエスト開発に対して、主従関係が名目上ではあるが逆(フィーチャー駆動、ウォーターフォール開発のような案件・設計からのforwardでマージリクエストは下流)。

大きく問題になっていないが、運用上の課題はある。

  • GitLabは非常に多くのソフトウェアを組み合わせて構成しており、CVSSで高スコアの脆弱性も半年に1,2個のペースで出ている。閉域網だが、定期的にバージョンアップしないと組織によってはセキュリティレベル上問題になる。
  • 新バージョン公開が頻繁にあり、1年でUIがかなり変わる。バージョンアップする場合、手順書維持コストに注意。

新基盤への移行と選定基準

今のベンダーが社内システム基盤に採用しているVM基盤が終了し、新しく某社クラウド基盤に移行することとなった。

例としてフルマネージドサービスを使う案内があったが、今回も個別VMインスタンスを作成し、依然と同じ構成で運用することにした。

理由は優先度順に以下。

  • 1: フルマネージドサービスを利用することで、ベンダーロックインが発生する。また、別基盤にする!と大移動することが普通に考えられるので、移植性を高めるためにVM構築に。
  • 2: フルマネージドサービスを利用するにはアカウントの整備が必要だが、登録・維持が大変。しかも他部署に申請しなければいけない。今回は、外部に管理委託するメリットが無い。(人の出入りが激しく、離任すればアクセス不可になるインターネット網であるため)
  • 3: 基盤運営部署のルール変更により運用が大きくかわるリスクがある。あまり、外部に依存したくない。
  • 4: UIが変わると手順書も作り直しになる。技術検証が面倒。

移行の詳しい手番や問題点・とりこし苦労については、また記事にする。

振り返って

実は、同じプロジェクトで、プルリクエスト型開発の提案を蹴られたことがある。 おそらく攻め方の問題で、おおよそ言われたのが「メリットのよくわからない開発手法を採用にすることによる教育コストや従来の開発プロセスを捨てることは良いとは思えない」あたりだそう。(自分は当時いなかったので正確なところは知らない)

今回はだまし討ちのような形だが、実質プルリクエスト開発の雛形を踏襲できるようになった。前向きな言葉で飾るなら、古典的なSIの現場でも、現場のプロセスや事情を汲んで地雷を踏まないようにすれば、良いツールや手法はどんどん取り組んでくれる。

そのためには、一度ツールをTUKATTEitリポジトリにGitLabを採用した話。CI基盤構築の参考になれば。

TL;DR

  • 大規模プロジェクトのソースコード管理/プルリクエスト管理のツールとしてGitLabを採用した。
  • 行基盤がクローズするので、クラウドの新基盤に移行した。
  • 移植性を重視したこと、5,6社が混在する大規模組織でクラウドサービスのアカウント管理をする体制がなかったことから、クラウドの各フルマネージドサービス(AWS CodeCommit / Azure DevOps / ECS / EKS など)の採用は見送った

身の上話

今、自分がベンダー側で参画している大規模プロジェクトでたまたまサーバー選定に意見できるようになり、ソースコード管理のツールとしてGitLab利用を提案した。 about.gitlab.com

というも、提案前は「ファイルシステムに直で置いたGitリポジトリSSHでアクセスする」原始的な運用をしており、1つの操作(メインブランチへの誤Commit/Push、ブランチ誤削除)で大問題が普通に起こるのに統制・権限制御が全く無かったのだ。開発に従事する人間がテスター・マネジメントを除いても100人超、関係会社5社を超えているなか、手心のある運用は崩壊するのが目に見えていた。

言葉の強弱はあるが、提案は以下のニュアンスだった気がする。

  • 今のソースコード管理では、マージの前後でミスが多発するうえトラッキングが難しいです。GitLabというツールを使って改善します。
  • 個別機能開発・不具合対応開始時に、特定の命名規則に従った個別ブランチとマージリクエスト(※GitLab版のプルリクエストの呼称)を作成して、今コミットしているソースコードは何なのか、Gitlabやブランチ見てわかるようにしてください。マージリクエスト使えば、ソースコードの差分のプレビューや後追いが簡単にできますよ。
  • 開発済みのソースコードを統合したメインブランチ(main、develop、各社開発済み資産ブランチ)への直接pushは制限として禁止します。各社開発済みのブランチをこちらで統合して、問題があれば連絡しますね。

浸透期間を要したものの、この目論見は成功したと思っている。

いくつか確信があり、その中の一つが、前運用時にやっていた「ソースコード開発差分を開発前・開発後でファイルのハードコピーをとって証跡としておく」プロセスの省略。

これが役に立つのであればよいが、最新ソースには色んなコミット入り乱れるから単純比較には使えず、リリース前の差分確認の参考になるにしても、配置ミスやバージョンが古くなるミスがあり信用できない(そもそもGit使ってやるべきだが、業界的に未習熟の人が管理・担当をやっていることがあるので、標準化や維持が難しい。歯がゆい)。結局、何か問題が起きた時に、当時何したのか?の責任追及以外に役に立たない。

そんな後ろ向きなエビデンス作りにミスや漏れに気を付けながら時間を割く必要があるのか?その思いは開発者、ひいてはチェックする側の人間も同様であり、GitLabのマージリクエスト作成時の差分プレビュー作成機能による自動化は強力な後押しになった。

構成と運用上の課題

GitLabは、仮想マシンを1台立ててRPMファイルをインストール。リバプロあり。ネットワークは閉域網のみ、インターネット公開無し。

  • サーバーの安定性は、まちまち。時々レスポンスが悪くなる。
  • 通常運用(ユーザー管理、マージリクエスト作成、ブランチ管理)の範囲では大きく不便はない。
  • ユーザーは、GitLab内に登録して管理。権限は、ブランチを直接メンテナンスする人間には「Owner」「Maintener」、一般開発者は「Developer」に割り当て。

また、マージリクエストの運用は、実際はRedmineの障害票チケットや別途変更管理票が親で、それのソースコード版という位置づけになっている。 一般的なプルリクエスト開発に対して、主従関係が名目上ではあるが逆(フィーチャー駆動、ウォーターフォール開発のような案件・設計からのforwardでマージリクエストは下流)。

大きく問題になっていないが、運用上の課題はある。

  • GitLabは非常に多くのソフトウェアを組み合わせて構成しており、CVSSで高スコアの脆弱性も半年に1,2個のペースで出ている。閉域網だが、定期的にバージョンアップしないと組織によってはセキュリティレベル上問題になる。
  • 新バージョン公開が頻繁にあり、1年でUIがかなり変わる。バージョンアップする場合、手順書維持コストに注意。

新基盤への移行と選定基準

今のベンダーが社内システム基盤に採用しているVM基盤が終了し、新しく某社クラウド基盤に移行することとなった。

例としてフルマネージドサービスを使う案内があったが、今回も個別VMインスタンスを作成し、依然と同じ構成で運用することにした。

理由は優先度順に以下。

  • 1: フルマネージドサービスを利用することで、ベンダーロックインが発生する。また、別基盤にする!と大移動することが普通に考えられるので、移植性を高めるためにVM構築に。
  • 2: フルマネージドサービスを利用するにはアカウントの整備が必要だが、登録・維持が大変。しかも他部署に申請しなければいけない。今回は、外部に管理委託するメリットが無い。(人の出入りが激しく、離任すればアクセス不可になるインターネット網であるため)
  • 3: 基盤運営部署のルール変更により運用が大きくかわるリスクがある。あまり、外部に依存したくない。
  • 4: UIが変わると手順書も作り直しになる。技術検証が面倒。

移行の詳しい手番や問題点・とりこし苦労については、また記事にする。

「頭の固い」現場を幸せにする

実は、同じプロジェクトで、プルリクエスト型開発の提案を蹴られたことがある。 おそらく攻め方の問題で、おおよそ言われたのが「メリットのよくわからない開発手法を採用にすることによる教育コストや従来の開発プロセスを捨てることは良いとは思えない」あたりだそう。(自分は当時いなかったので正確なところは知らない)

今回はだまし討ちのような形だが、実質プルリクエスト開発の雛形を踏襲できるようになった。前向きな言葉で飾るなら、古典的なSIの現場でも、現場のプロセスや事情を汲んで地雷を踏まないようにすれば、良いツールや手法はどんどん取り組んでくれる。

エバンジェリストではないが、そのために一度身をもってツールを使って特性や運用イメージを事前に知って練る必要がある。 今回はGitLabを主体の話だが、導入判断にはGitの特性を始めとしたツールチェーン上にある各要素のメリット・運用したときに発生するであろうデメリット、広義にとれば、ソースコードのハードコピーの運用、Redmineでの障害票管理がこのツールにどうつながってくるのかも想像しないとヒットを打てるかすら難しい。

つくづく、改善するには蓄積が先にあって、メリットやコスト最適化は時期をもって供されるものと感じざるを得ない。

【Oracle】DBMS_CRYPTOパッケージを用いてデータを暗号化する

TL;DR

  • OracleDBMS_CRYPTOという暗号化関数がまとまった標準パッケージがある。
  • 引数のデータ型はRAW型(デフォルトで最大2000bytes、設定変更で32757bytes)。CHAR/VARCHAR型との変換はUTL_I18Nパッケージを用いる。
  • 暗号化関数DBMS_CRYPTO.ENCRYPT関数 / 復号化DBMS_CRYPTO.DECRYPT関数は非DETERMINISTICなので直接関数インデックスに用いることはできない。ストアドファンクションでラップする必要がある。
  • 暗号化 / 復号化キーを隠匿するのはできるが各方面満点の解はない

前提

  • Oracle19c

DBMS_CRYPTOパッケージ

公式ドキュメント

docs.oracle.com

利用の前提条件

  • Oracle19c現在、追加ライセンス不要。
  • 初期では権限不足でどのユーザーも使えないため、権限付与SQLの実行要(たぶんsysユーザーが必要)
-- 権限付与
GRANT execute ON SYS.DBMS_CRYPTO TO youruser;

利用例

使い方例(暗号化)

-- 暗号化
SELECT
 DBMS_CRYPTO.ENCRYPT(
    UTL_I18N.STRING_TO_RAW('暗号化対象データ', 'AL32UTF8'),
    6+256+4096,  -- 暗号化指定。このパラメータはAES128
    HEXTORAW('010203040506070809a0b0c0d0e0f000') -- 暗号化キー
  )
  AS crypt
FROM
  dual;

result

CRYPT
--------------------------------------------------------------------------------
2F5C489FB4BE399A4EB81FFBA6B6E28645B7060B5EC1D93F63571A4E0F119C02
  • 第二引数の値は、DBMS_CRYPTOパッケージ配下の定数を参照。
    • URL:DBMS_CRYPTO
    • 例えば 6 + 256 + 4096 は、以下で確認できる
SET SERVEROUTPUT ON

BEGIN
   DBMS_OUTPUT.PUT_LINE(DBMS_CRYPTO.ENCRYPT_AES128);
   DBMS_OUTPUT.PUT_LINE(DBMS_CRYPTO.CHAIN_CBC);
   DBMS_OUTPUT.PUT_LINE(DBMS_CRYPTO.PAD_PKCS5);
END;
/

使い方例(復号化)

-- 復号化
SELECT
 UTL_I18N.RAW_TO_NCHAR(
   DBMS_CRYPTO.DECRYPT(
      crypt,
      6+256+4096,
      HEXTORAW('010203040506070809a0b0c0d0e0f000')
    )
  , 'AL32UTF8') as plain
FROM
  (SELECT
   DBMS_CRYPTO.ENCRYPT(
      UTL_I18N.STRING_TO_RAW('暗号化対象データ', 'AL32UTF8'),
      6+256+4096, 
      HEXTORAW('010203040506070809a0b0c0d0e0f000')
  ) AS crypt
  FROM
    dual
  );
  • 結果はRAW型なので RAW_TO_CHARRAW_TO_NCHAR で復号する必要あり
  • 暗号アルゴリズムによって、暗号キー・復号キーが異なる場合がある。(RSAなどが該当)

関数インデックス

  • 以下はエラーとなる。
CREATE TABLE sample(crypt RAW(2000));
CREATE INDEX idx_sample ON sample(DBMS_CRYPTO.DECRYPT(crypt, 0, HEXTORAW('00')));
CREATE INDEX idx_sample ON sample(DBMS_CRYPTO.DECRYPT(crypt, 0, HEXTORAW('00')))
                                  *
行1でエラーが発生しました。:
ORA-30553: 関数がDETERMINISTICではありません。
  • 以下のように、DETERMINISTICなストアドファンクションを定義することで回避できる。
CREATE OR REPLACE FUNCTION DECRYPT_AES128
  (
    -- 暗号データ
    src IN VARCHAR2,
    -- 復号キー。16bytesであること
    key IN VARCHAR2
  )
  RETURN RAW DETERMINISTIC
IS
BEGIN
  RETURN DBMS_CRYPTO.DECRYPT(
    UTL_I18N.STRING_TO_RAW(src, 'AL32UTF8'),
    DBMS_CRYPTO.ENCRYPT_AES128 +
    DBMS_CRYPTO.CHAIN_CBC +
    DBMS_CRYPTO.PAD_PKCS5,
    UTL_I18N.STRING_TO_RAW(key, 'AL32UTF8')
  );
END;
/
CREATE INDEX idx_sample ON sample(DECRYPT_AES128(crypt, 0, HEXTORAW('00')))
  • 後述するが、関数インデックスはデータファイル上暗号化されないので注意。

暗号化キーの隠匿化

  • SQLのパラメータとしてキー値を渡したりSQL文にベタ書きすると、Oracle内ログ、アプリログ、通信にキーが曝露するのでセキュリティ上非常によくない。
  • 色々方式はあるが、PL/SQL内にキーを隠匿し、SOURCEも隠匿する手法にいきついたので紹介

SOURCEを秘匿化しながらストアドファンクションを定義

DECLARE
   ddl_text VARCHAR2(32767);
   key_nchar VARCHAR2(32) := '010203040506070809a0b0c0d0e0f000';

   FUNCTION generaye_ENCRYPT_AES128_DDL RETURN VARCHAR2
   IS
   BEGIN
      return 'CREATE OR REPLACE FUNCTION ENCRYPT_AES128' ||
         '  (' ||
         '    src IN VARCHAR2' ||
         '  )' ||
         '  RETURN RAW DETERMINISTIC' ||
         ' IS' ||
         ' BEGIN' ||
         '  RETURN DBMS_CRYPTO.ENCRYPT(' ||
         '    UTL_I18N.STRING_TO_RAW(src, ''AL32UTF8''),' ||
         '    DBMS_CRYPTO.ENCRYPT_AES128 +' ||
         '    DBMS_CRYPTO.CHAIN_CBC +' ||
         '    DBMS_CRYPTO.PAD_PKCS5,' ||
         '    HEXTORAW('''|| key_nchar ||''')' ||
         '  );' ||
         'END;';
   END generaye_ENCRYPT_AES128_DDL;
   FUNCTION generaye_DECRYPT_AES128_DDL RETURN VARCHAR2
   IS
   BEGIN
      return 'CREATE OR REPLACE FUNCTION DECRYPT_AES128' ||
         '  (' ||
         '    src IN RAW' ||
         '  )' ||
         '  RETURN VARCHAR2 DETERMINISTIC' ||
         ' IS' ||
         ' BEGIN' ||
         '  RETURN UTL_I18N.RAW_TO_NCHAR(DBMS_CRYPTO.DECRYPT(' ||
         '    src,' ||
         '    DBMS_CRYPTO.ENCRYPT_AES128 +' ||
         '    DBMS_CRYPTO.CHAIN_CBC +' ||
         '    DBMS_CRYPTO.PAD_PKCS5,' ||
         '    HEXTORAW('''|| key_nchar ||''')' ||
         '  ), ''AL32UTF8'');' ||
         'END;';
   END generaye_DECRYPT_AES128_DDL;
BEGIN
   ddl_text := generaye_ENCRYPT_AES128_DDL();
   EXECUTE IMMEDIATE ddl_text;
   SYS.DBMS_DDL.CREATE_WRAPPED(ddl_text);
   ddl_text := generaye_DECRYPT_AES128_DDL();
   EXECUTE IMMEDIATE ddl_text;
   SYS.DBMS_DDL.CREATE_WRAPPED(ddl_text);
END;
/
  • デモ
select
 ENCRYPT_AES128('テストデータ') as crypt,
 DECRYPT_AES128(ENCRYPT_AES128('テストデータ')) as plain
from dual;
CRYPT
--------------------------------------------------------------------------------
PLAIN
--------------------------------------------------------------------------------
21E108C3DCA3AFFDAC709FB1079F71724C90C3EB22FC90E7D03EC066598568D8
テストデータ
  • 仕組みはよく分からないが、SYS.DBMS_DDL.CREATE_WRAPPED()を介すことでSOURCEが簡単に見れなくなる
  • Oracleのドキュメントを見ると動的に生成、とあるので、もしかしたらパフォーマンスに影響があるかもしれない(未検証)
SELECT text FROM ALL_SOURCE WHERE name = 'ENCRYPT_AES128';
FUNCTION ENCRYPT_AES128 wrapped
a000000
369
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
8
12a 128
rcNM2xfPeGeX3nLRY90YTcVHg+owg3nQDEgVZy+ix4kZiJlGlznTgNjUhvtgN2E96/8XKgYS
te98VEs30mFBh1xkI2H8uhvGK/l78NQCUdjjYInR42xy0nnbSF+Joq33V80CoUcoKtyQinr4
DiI3NyfE3M4d3vxM49YNkBmB1g2xedLplesOBkKkDfD63/IBtpdHnyszReXCz8ALtVJ6G0pP
TqCzx6ANEPB769u52UCVylVTD3kgjYieiXU4SkQZCDeeTxJ2uNu9F3GmkSnuzylTk7xM+2ha
DIA=

セキュリティ的な評価

脅威 評価 追加対策の余地
OSに不正ログインされ、Oracleのテーブルデータファイルを詐取される 〇:暗号化されており、復号キーも漏洩していない
OSに不正ログインされ、Oracleのインデックスデータファイルを詐取される ×:インデックス値は平文で保存されている Oracle Advanced Security(有料オプション)のTDEでデータファイルを暗号化する。問題のあるキーの組み合わせ(個人名, 電話番号の複合インデックスなど)を用いない、インデックス化を避けるなどの設計による対処
DBに不正ログインされ、SQLを実行される △:復号化関数や手法を知っていれば平文を漏洩してしまう 関数名の難読化、手掛かりにいきつくまでの妨害・ログの秘匿化
DBにログインした作業者による詐取 △:復号化関数や手法を知っていれば平文を漏洩してしまう 保守ユーザ/アプリユーザの分離・権限の制限
アプリケーション脆弱性によるSQLインジェクション経由での詐取 〇:復号化関数の存在を知ることは困難と考えられるため、暗号化したデータしか表示されない

TDEとの比較

  • TDEは、Oracle Advanced Security(有料オプション)の機能の1つ。
  • TDEは、Oracleのデータファイルを暗号化する。そのため、SQL実行による参照は保護されず、アプリケーションからのSQLインジェクションにも対応できない。
  • 情報のマスキングは、Oracle Advanced Securtyの他オプションでも可能だが、特定ユーザーはマスキング項目を非表示にするなどの作業者へのいじわると、暗号化による保護というよりは内部統制のソリューションであり、DBへの不正接続・SQLインジェクションなどによる任意クエリ実行の対策にはならないと考えている。
    • 詳しく調べてないので、有識者に聞いてみたい。

WindowsPC同士で有線LAN1本直結でリモートデスクトップ接続する

クロスケーブルを買って接続

ストレートケーブルとクロスケーブルを見分ける方法 | バッファロー

通常のLANケーブル(ストレートケーブル)に対して、 端子のピンの並びが端と端同士で鏡のように左右対称に なっているLANケーブルのこと。 PC同士の接続に使う。ルータやハブには使えない。

IPアドレスを手動で設定する

Windows 10でLANケーブルでPC同士を繋いでファイル共有 - キリウ君が読まないノート

WindowsPCを接続しただけでは、DHCP(自動でIPアドレスが 割り振られる仕組み)が働かない。 通常、ブロードバンドルータや企業ネットワークなどでは DHCPサーバーが担当。)

よくわからなければ、サイトの通りに設定すると間違いがない。

蛇足 プライベートIPアドレスとは

なお、元のLANに接続しなおして「IPアドレスが重複しています」 などのエラーが出たら、即時IPアドレスを自動設定に戻すようにする。 (大目玉くらいます)

リモートデスクトップで接続される側のWindowsリモートデスクトップを有効にする

PC でリモート デスクトップを有効にする | Microsoft Learn

リモートデスクトップで接続される側のWindowsの「パブリックネットワーク」のファイアウォールを切る

直接LANで接続している場合必ずパブリックネットワークになり、 デフォルトではファイル共有およびリモートデスクトップ接続が無効となる。 セキュリティソフトやWindowsファイアウォールの設定を見て、 パブリックネットワークの設定を変える。

Norton Intenet Security リモートデスクトップ許可設定 - KuroNeko666’s blog

リモートデスクトップのWindowsファイアウォール設定 | 日記というほどでも

以上

これで接続できなかったら、pingとかで地道に検証。

謎シチュに至った訳

初学者がUMLだけやっても意味がないのでは?

身も蓋もない言い方

設計は沼であり、大事な仕事・作業・人間生活にかかることであればちゃんと武装して臨むべき。

UMLは可視化ツール

クラスを中心としたソースコードを書けば、対応するUMLは半ば機械的に生成できる。 UMLは地図であって、極地的な地形であってもとりあえずそのままに書けてしまう。

良い設計は、コンセプトを伴ったパターンを持つことが一種指標に思える。 例えば、クラス図は汎化を表現できるが、以下のように指向するとよい設計につながる。

  • あるデスクトップアプリケーションのデータ書き込み処理は、同じデータを固定長レイアウト、JSON形式、CSV形式の3パターンで表現する。
  • 3パターンの形式を決定するのは、書き込み時にGUI指定する。それ以外のファイル書き込み時のハンドリングはすべて共通。
  • それぞれの派生クラスを「生成」し、後続のファイル書き込み処理に、書き込みデータ供給の共通インタフェースを通じて処理をさせる。

こう言葉で書くとながったらしいことを、UMLは記号化してくれる。 しかし、この複雑さを簡略化はしてくれず、説明を端折ると謎の図になる。

実装パターンを豊富に知っているのであれば、思いつくままパズルの要領でつなぎ合わせて6,7個ぐらいの概念を同時に入れたところで依存性の糸の絡まり具合を可視化し、ここは切れるとかこの概念は相性が悪そうだとかを診断するためのツールになる。

初学者にとってのUML

まだ学生の頃にカリキュラムとしてUMLを触れた当時は価値がわからなかった。 簡単なMVCモデルの1画面をクラス図に書いただけで整理の必要が全くなかったのが一番の原因だが、 複雑なものを表現したとしても、知見不足で書いてみたのでは結局わからずじまいだったかもしれない。

そもそも、UML関連の学習コンテンツは説明が悪いことが多い。 「集約とは、集めて持つことである」「包含とは内部にオブジェクトを隠ぺいして持つことである」「依存はそのクラスを使っていることである」 と定義はわかるのが、なんのために依存するとか、この構造を持つことで特定の処理時にパターン化できるとか、ケーススタディ的な学びがUMLと一緒にできる例についに出会うことはなかった。 「設計とかコーディングのときに気づき内省しものにせよ」と寿司職人さながらのマインドはまだしも、UMLは握ってモチベーションに駆られるかの観点から題材の悪さしか印象にない。

設計とUML

UMLは良くも悪くも可視化ツールだ。 なので、パターンとコンセプトのある設計を表現してみて確からしさを検証するための手遊びの道具であり、 実際の実装や他の図と反復しながら多角的に検証したり、豊富なナレッジベースを並べてみて組み合わせを評価するのが一番道具として生きると考えている。 もし、UMLがしっくりこないとか意味が解らないのであれば、少し仕事や勉強から逸れたことをして、思い切り複雑で新しいことをしたときにでも思い出して無理やり書いてみるとどうだろうか。

【ExcelVBA】VBAはクラス指向より手続き型でFATに作りたい

前置き

VBAでもクラスは作成できる。

qiita.com

しかし、フォルダや階層による小分けができない。 例えば設定ファイルの保持やパースのために作ったConfigクラス、特定ファイルの書き出しのために作ったExternalXXXCSVFileクラスやExternalYYYCSVFile、内部のファイルの保持のために作ったTempFileクラス、その他値の保持用だったりビジネスロジックがぐちゃぐちゃに入り組んだりする実態が同じフォルダに入る。 そこそこの規模のアプリを作ろうとしたとき、違う考え方の領域が10個ぐらい、系3,40個のクラスが並列に並ぶことになる。これはWeb系の言語でやっているようなスケーラブル(脳死で拡張可能)なオブジェクト指向なクラスの管理だろうか?

プロジェクト(=Excelブックやxlamファイル)で分ければできるが、全部読み込むようにするのは手間だし分割も面倒、本末転倒だ。

そこそこ小さい実装ならまあいい感じの実装にはなるだろう、しかし個人としては、VBAでクラス指向*1 で設計するのはアンチパターンと位置付けるに至った。

MVCは、1つの標準モジュール/Excelシート/シートVBAを1つの「M」「V」「C」に見立ててみる

Web系に馴染みのある方であればMVCパターンを適用したくなるだろう。 ここで、それぞれの要素をModel(処理の本体)、View(ユーザーインタフェース)、Contoller(MとVの繋ぎ)で考える。(※Web系実装のMVCは通常、Mはステートフル=DBやデータなどの状態を持ち更新処理などがあるが、ここでは基本的にステートレス=データ保持無しのため、実行時パラメータによって完全に決まるものとする。)

V。Excelシートそのもの。 C。Excelシートをクリックしたときに実行するハンドラ。色々な変換処理がある。Mを呼び出す。 M。Cの結果を受けて、何かしら外部ファイルを出力したり作用したりするメソッドのみの存在。単独テストが可能。

V → Cへの繋ぎは、ExcelのRangeやCellといった各種APIで代用となる。ここら辺が特にツライが、データ化すればこっちのもの。FormやDto、Entity、Recordといった実体が欲しいのであればCreateObject("Dictionary.Scripting")で連想配列を使ったり、そこだけクラスモジュール化してもよい。 C → Mへの繋ぎは、V→Cでデータ化したものをそのまま受け渡すだけでよい。

以上、やりたいことは、引数と戻り値だけの標準モジュールで実装できないだろうか。

モジュールとImmutableを基本に設計・実装する

ローカル変数以外に、メモリ中に状態を持たず、処理結果や確保したリソースを引き続き保持したければすべて引数・戻り値を介して取得・保持し、メンバー変数やグローバル変数は必要時以外排除すると、自然とImmutableな実装は達成される。 細かい項目の受け渡しが面倒であれば、そこだけクラス化や連想配列化によりまとめて処理してしまえばよい。ここまで徹底的にやれば、晴れてクラス実装を手放せる。

代わりに、1つのモジュールの責務が肥大化するが、Excel VBAはそもそもスコープが小さくなる傾向にあるので、よほどの場合を除きコントロール可能な範囲に収まるはず。(そもそも、VBAがコントロール不能なぐらい肥大化している場合、もはやExcel VBA以外の実装を用いたほうがメリットが大きいというような事態に陥ってないだろうか?)

*1:「クラス指向」の言い回しは、オブジェクト指向に造詣の深い方にとって違和感の塊だろう、しかしあえて揶揄している。多態を持たず、静的なプログラム構造によって実際の動作および俯瞰図が完成するのであれば、メモリ上に実態を展開し実行時情報を持つというオブジェクト指向の原典的な利点の1つは別になくても、クラスという書式でカプセル化、レイヤ化、関心や責任の分離は実現できる。そしてその3点はC言語のような純手続き型言語でも設計によって十分可能であり、現実に、1970年代に軍事系のC言語の開発プロジェクトで達成されたという研究もある。クラス名のパターンが設計のすべてなのであれば、関数名+引数にとる構造体のグループでほぼ誤差なく手続き型に落とせる。

【Excel VBA】ファイルの絶対パスを取得する

カレントディレクト

Sub 使いないやつ()
    Debug.Print CreateObject("Scripting.FileSystemObject").GetAbsolutePathName("./")
    Debug.Print CurDir
End Sub
  • どっちも、デフォルトだと%UsersProfile%\Documents(マイドキュメント)を指す。
  • Excelのワークブックのパス基準の絶対パス取得は以下の通り。
Public Function AbsPath(String RelativePath) As String
On Error GoTo HANDLING
    Dim DirBK As String
    DirBK = CurDir
    ChDrive Left(ThisWorkbook.Path, 1)
    ChDir ThisWorkbook.Path
    AbsPath = CreateObject("Scripting.FileSystemObject").GetAbsolutePathName(RelativePath)
    ChDrive Left(DirBK, 1)
    ChDir DirBK
    Exit Function
    
HANDLING:
    Debug.Log ("[ERROR]AbsPath():" & ERR.Description)
    ERR.Raise ERR.Number, ERR.Source, ERR.Description, ERR.HelpFile, ERR.HelpContext
    
End Function()
  • FileSystemObjectやChDirを使わないレシピ
Public Function AbsPath(Path As String) As String
On Error GoTo HANDLING

    If (InStr(Path, ":") <> 2) Then
        Path = ThisWorkbook.Path & "\" & Path
    Else
        Path = Path
    End If
    
    
    Dim idx As Long
    Do While InStr(Path, "..\") > 0
        idx = InStr(Path, "..\")
        
        Dim idxPrevSep As Long
        idxPrevSep = InStrRev(Path, "\", idx - 2)
        If (idxPrevSep = 0) Then
            Exit Do
        End If
        
        Path = Left(Path, idxPrevSep - 1) & Mid(Path, idx + 2)
    Loop
    
    Path = Replace(Path, ".\", "")
    AbsPath = Path
    
    Exit Function
    
HANDLING:
    Debug.Log ("[ERROR]AbsPath():" & ERR.Description)
    ERR.Raise ERR.Number, ERR.Source, ERR.Description, ERR.HelpFile, ERR.HelpContext
    
End Function