NextCloudでアップロード時に不明なエラーが発生する。

大きなファイルをアップロードしていると「不明なエラー」が発生します。ログを見ると以下の様なエラーが発生していました。どうも帯域が狭いために、アップロード中にタイムアウトエラーが発生しているようです。

Sabre\DAV\Exception\BadRequest: Expected filesize of 10485760 bytes but read (from Nextcloud client) and wrote (to Nextcloud storage) 5368032 bytes. Could either be a network problem on the sending side or a problem writing to the storage on the server side.

10,485,760 bytesは標準のチャンクサイズです。Nextcloudではアップロードをチャンクサイズのデータに分解して処理しています。10MB分送信する前にタイムアウトが発生してしまっていたようです。

タイムアウトを長くしても良いのですが、設定対象が多岐に渡るので、ここはチャンクサイズを5MBに調整する方向で対処します。occコマンドで設定を変更できますので、以下のコマンドを実行してチャンクサイズを変更します。

$ sudo docker-compose exec --user www-data nextcloud php occ config:app:set files max_chunk_size --value 5242880
Config value max_chunk_size for app files set to 5242880

再度ファイルをアップロードしたところ、エラーになる事無く上手く動いているようです。

NextCloudのアクセスログ管理

Nextcloudには標準で監査ログ機能があります。インターネットから接続出来る状態で運用するなら、監理者の責任としてログぐらいは残して起きたいところです。Docker上で動作させているNextCloudのログ設定をおこないます。

監査ログ出力のための設定

「Auditing / Logging」プラグインが有効になっていることを確認して下さい。標準で有効になっているはずです。

以下のコマンドを実行してログの設定をログレベル:1、タイムズーんを日本に変更します。現時点(バージョン23.0.0)では–rotate-sizeの設定は機能しません。明示的にNextcloudのLog Rotateを無効にしておき、別にlogrotateを設定する事にします。

$ sudo docker-compose exec --user www-data nextcloud php occ log:manage --level=info --timezone Asia/Tokyo
Enabled logging backend: file
Log level: Info (1)
Log timezone: Asia/Tokyo

$ sudo docker-compose exec --user www-data nextcloud php occ log:file --rotate-size=0
Log backend file: enabled
Log file: /var/www/html/data/nextcloud.log
Rotate at: disabled

これで./html/data/audit.logに監査ログが出力されるようになるはずです。

Log Rotateの設定

/etc/logrotate.d/nextcloudを以下の通り作成します。パス名の/var/docker-nextcloudは自信の環境に置き換えて下さい。

/var/docker-nextcloud/html/data/nextcloud.log {
  monthly
  rotate 12
  missingok
  notifempty
  compress
  delaycompress
  postrotate
    touch /var/docker-nextcloud/html/data/nextcloud.log
    chown www-data:www-data /var/docker-nextcloud/html/data/nextcloud.log
    chmod 640 /var/docker-nextcloud/html/data/nextcloud.log
  endscript
}

/etc/logrotate.d/nextcloudauditを以下の通り作成します。

/var/docker-nextcloud/html/data/audit.log {
  monthly
  rotate 12
  missingok
  notifempty
  compress
  delaycompress
  postrotate
    touch /var/docker-nextcloud/html/data/audit.log
    chown www-data:www-data /var/docker-nextcloud/html/data/audit.log
    chmod 640 /var/docker-nextcloud/html/data/audit.log
  endscript
}

以下の通りlogrotateデーモンを再起動します。

$ sudo service logrotate restart

以上で毎月ログが圧縮されて別ファイルとなり、12ヶ月でローテーションされます。

NextCloud設定画面のセキュリティ&セットアップ警告に対応する

NextCloudでWEBストレージサービスを自前で作成する」でNextCloudのDocker環境を構築しましたが、そのままだと設定→概要でセキュリティ警告が表示されています。消せる警告は消していきたいと思います。

信頼できるプロキシーの設定

docker-compose.ymlにTRUSTED_PROXIESとOVERWRITEHOSTを追加します。

services:
  nextcloud:
    ...
    environment:
      ...
      - TRUSTED_PROXIES=127.0.0.1
      - OVERWRITEHOST=next.code-lab.net
      - OVERWRITEPROTOCOL=https
      ...

以下のコマンドを実行して設定を反映します。

sudo docker-compose up -d

「リバースプロキシヘッダーの構成が正しくないか、信頼できるプロキシからNextcloudにアクセスしています。そうでない場合、これはセキュリティに問題があり、攻撃者がNextcloudを表示できるようにIPアドレスを偽装することができます。詳細については、ドキュメント↗をご覧ください。」の警告が消えて居ることを確認して下さい。

Strict-Transport-Securityの設定

リバースプロキシサーバーにはNginxを使用しているので、/etc/nginx/sites-available/next.code-lab.net.confを編集して「add_header Strict-Transport-Security ‘max-age=15552000; includeSubDomains; preload’;」を追加します。

server {
    ...
    add_header Strict-Transport-Security 'max-age=15552000; includeSubDomains; preload';
    ...
}

以下のコマンドを実行して設定を反映します。

sudo service nginx restart

「Strict-Transport-Security “HTTP ヘッダーの秒数が少なくとも”15552000” に設定されていません。セキュリティを強化するには、セキュリティのヒント↗で説明されているようにHSTSを有効にすることをお勧めします。」 の警告が消えて居ることを確認して下さい。

default_phone_regionの設定

./html/config/config.phpを編集してdefault_phone_regionを追加します。残念ながらDockerの環境変数から指定する事はできないようです。

<?php
$CONFIG = array (
 ...
 'default_phone_region' => 'JP',
 ...
);

以下のコマンドを実行して設定を反映します。

sudo docker-compose restart

「ご使用のシステムには、デフォルトの電話地域が設定されていません。これは、国コードなしでプロファイル設定の電話番号を検証するために必要です。国コードなしで番号を許可するには、地域のそれぞれの ISO3166-1コード↗とともに “default_phone_region” を設定ファイルに追加してください。」 の警告が消えて居ることを確認して下さい。

DBにインデックスを作成する

以下のコマンドを実行します。

$ sudo docker-compose exec --user www-data nextcloud php occ db:add-missing-indices
Check indices of the share table.
Check indices of the filecache table.
Adding additional size index to the filecache table, this can take some time...
Filecache table updated successfully.
Adding additional path index to the filecache table, this can take some time...
Filecache table updated successfully.
Check indices of the twofactor_providers table.
Check indices of the login_flow_v2 table.
Check indices of the whats_new table.
Check indices of the cards table.
Check indices of the cards_properties table.
Check indices of the calendarobjects_props table.
Check indices of the schedulingobjects table.
Check indices of the oc_properties table.

「データベースにいくつかのインデックスがありません。~」 の警告が消えて居ることを確認して下さい。

「php-imagickモジュールはSVGをサポートしていません。」の警告が残っています。Dockerイメージを更新すれば良さそうですが、メリットが薄そうなのでこの警告は容認する事とします。

Nextcloudにアップロードできるファイルサイズ上限を増やす

デフォルトの設定のままだと512MBを超えるファイルサイズを扱うことが出来ません。以下の設定を変更してアップロードできるファイルサイズの上限を変更します。

Nginxの.confにclient_max_body_size 51200M;を追加します。

 server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    ...
    client_max_body_size 51200M;
    ...
}

以下の通りdocker-compose.ymlにPHP_MEMORY_LIMIT=512MとPHP_UPLOAD_LIMIT=51200Mを追加します。

version: '3'

volumes:
  nextcloud:
  nextcloud-db:

services:
  nextcloud-db:
    image: mariadb
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --innodb-file-per-table=1 --skip-innodb-read-only-compressed
    restart: always
    ports:
      - 3307:3306
    volumes:
      - ./mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${ENV_MYSQL_ROOT_PASSWORD}
      - MYSQL_PASSWORD=${ENV_MYSQL_PASSWORD}
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud

  nextcloud:
    image: nextcloud
    ports:
      - 8081:80
    links:
      - nextcloud-db
    volumes:
      - ./html:/var/www/html
    restart: always
    environment:
      - NEXTCLOUD_TRUSTED_DOMAINS='next.code-lab.net'
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=${ENV_MYSQL_PASSWORD}
      - MYSQL_HOST=nextcloud-db:3306
      - OBJECTSTORE_S3_HOST=ewr1.vultrobjects.com
      - OBJECTSTORE_S3_BUCKET=nextcloud-root
      - OBJECTSTORE_S3_KEY=S3_KEY
      - OBJECTSTORE_S3_SECRET=S3_SECRET
      - OBJECTSTORE_S3_PORT=443
      - OBJECTSTORE_S3_SSL=true
      - OVERWRITEPROTOCOL=https
      - PHP_MEMORY_LIMIT=512M
      - PHP_UPLOAD_LIMIT=51200M

NginxとDockerコンポーネントを再起動します。

sudo service nginx restart
sudo docker-compose stop
duso docker-compose up -d

その後にNextcloud上で設定→システムを参照すると以下の様に最大アップロードサイズが大きくなっているかと思います。

NextCloudでWEBストレージサービスを自前で作成するよ

リモートワークや非PPAP対応のために、WEBストレージサービスが使われることが増えています。でもWEBストレージサービスの多くはユーザーライセンス方式・・・消費する容量が少なくとも、使用頻度が低くとも、ユーザー数が増えるとライセンス料がかさんでしまいます。そこでオープンソースのNextCloudを活用して時前のWEBストレージサービスを構築することを考えてみます。

NextCloudのインストール

NextCloudをインストールする方法はいくつかあります。AWSにはNextCloud公式のAMIファイル(355428426254/Nextcloud-21.0.1-RHEL8-ja_JP)があるので、これを使っても容易にサーバーを作ることが出来ます。

今回は運用の容易さを考えてNextCloud公式のDocker Image(https://hub.docker.com/_/nextcloud)を使って構築したいと思います。DockerおよびDocker-Composeが動作する環境を構築するところは割愛します。

NextCloudにアップロードしたファイルはプライマリストレージ(通常は”./html/data”)に保存されます。今回はストレージコストを抑えるために、プライマリストレージにはAWS S3を指定することにします。

docker-compose.ymlを用意します。

version: '3'

volumes:
  nextcloud:
  nextcloud-db:

services:
  nextcloud-db:
    image: mariadb
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --innodb-file-per-table=1 --skip-innodb-read-only-compressed
    restart: always
    ports:
      - 3306:3306
    volumes:
      - ./mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${ENV_MYSQL_ROOT_PASSWORD}
      - MYSQL_PASSWORD=${ENV_MYSQL_PASSWORD}
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud

  nextcloud:
    image: nextcloud
    ports:
      - 8081:80
    links:
      - nextcloud-db
    volumes:
      - ./html:/var/www/html
    restart: always
    environment:
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=${ENV_MYSQL_PASSWORD}
      - MYSQL_HOST=nextcloud-db:3306
      - OBJECTSTORE_S3_HOST=s3.region.amazonaws.com
      - OBJECTSTORE_S3_BUCKET=bucketname
      - OBJECTSTORE_S3_KEY=[accesskey]
      - OBJECTSTORE_S3_SECRET=[secretkey]
      - OBJECTSTORE_S3_PORT=443
      - OBJECTSTORE_S3_SSL=true
      - OVERWRITEPROTOCOL=https

.envファイルを用意します。

# docker-compose内で利用する環境変数をここで設定します。
# 下記2つの環境変数に、適当な文字列を設定してください。
ENV_MYSQL_ROOT_PASSWORD=root_password
ENV_MYSQL_PASSWORD=user_password

nginxでリバースプロキシを構成すためのconfファイル(/etc/nginx/sites-available/next.example.net.conf)を作成します。

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

    server_name next.example.net;
    return 301 https://$host$request_uri;
 }

 server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/next.example.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/next.example.net/privkey.pem;

    server_name next.example.net;

    client_max_body_size 20M;
    client_header_buffer_size 64k;
    large_client_header_buffers 4 64k;

    proxy_set_header    Host               $host;
    proxy_set_header    X-Real-IP          $remote_addr;
    proxy_set_header    X-Forwarded-Proto  https;
    proxy_set_header    X-Forwarded-Host   $host;
    proxy_set_header    X-Forwarded-Server $host;
    proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;

    proxy_redirect      off;
    proxy_connect_timeout       3600;
    proxy_send_timeout          3600;
    proxy_read_timeout          3600;
    send_timeout                3600;

    location / {
        proxy_pass    http://localhost:8081/;
    }

    location /.well-known/carddav {
        return 301 $scheme://$host/remote.php/dav;
    }

    location /.well-known/caldav {
        return 301 $scheme://$host/remote.php/dav;
    }
}

以上、必要な設定の記述が終わりましたので、以下のコマンドを実行して起動します。

# sites-enabledにシンボリックリンクを作成
sudo ln -s /etc/nginx/sites-available/next.example.com /etc/nginx/sites-enabled/next.example.com
# nginxサービスを再起動
sudo service nginx restart
# dockerを起動
sudo docker-compose up

WEBブラウザでhttps://next.example.net/を開きます。

以下の画面で監理者アカウントのユーザー名とパスワードを指定しして「セットアップを完了します」をクリックしてください。しばらく待つと初期設定が終わり、NextCloudにログインできます。

NextCloudの基本的な初期設定

メールサーバーの指定

右上の○アイコンからメニューを開き設定を選択します。最初に個人情報タブのメールを設定しておきます。ここを設定しておかないとSMTPサーバーの設定をできません。

続いて基本設定タブを選択します。メールサーバーの設定を行います。

多要素認証の設定

右上の○アイコンからメニューを開き アプリを選択します。セキュリティタブから’OpenOTP Two Factor Authentication’と’Two-Factor Email’をダウンロードして有効にします。

これで設定のセキュリティタブに二要素認証の項目が追加されます。

Enabled Two Factor Emailをクリックすると認証用のメールが届きますので、認証コードを入力します。

TOTPの有効化のチェックをするとQRコードが表示されるので、TOTPに対応したGoogle Authenticater等のアプリでQRコードを読み取り、ワンタイムパスワードを入力して認証します。

外部ストレージの有効化

NextCloud上にアップロードしたファイルは’urn:oid:100’といったファイル名に保管されます。これらのファイルは NextCloud 上で無ければ確認する事ができません。これに対して外部ストレージのファイルは、画面上に表示されているファイル名そのままで保存されています。

外部ストレージ上のファイルはNextCloud以外からも読み書き出来ます。既存NASからのデータ移行や、NextCloud以外のシステムとの連携など、便利に使用する事ができます。ユーザー単位やユーザーグループ単位でアクセス制限をかける事が出来るので、部署単位での共有フォルダなども外部ストレージを使用すると便利です。

外部ストレージを使用するにはメニューからアプリを選択して無効なアプリタブにある’External storage support’を有効にします。その後、メニューから設定を開くと外部ストレージタブが追加されています。

上記では標準共有という名称でS3のバケットに接続しています。

楽天CASAのLTEインジケーターが橙点滅のままで動かない

楽天CASAのLTEインジケーターが橙(オレンジ)点滅や緑点滅を繰り返していて、緑点灯状態にならない場合があります。そんなときは楽天モバイルのCASAのサポートに電話してください。

楽天CASAのマニュアルやWEBには記載がありませんが、不正売買や登録住所以外での不正利用を防ぐために、LTE中継機としての動作を停止させる機能があります。ルーターなどネットワーク機器の交換、回線の変更などにより、最初に動作させたのとネットワーク環境が変化すると、別の場所に移動した可能性があるとしてロックしてしまうようです。

LTE中継機としての機能がロックされてしまうと、ユーザー側では解除できません。楽天CASAの電話サポートに連絡すると、5分程度でロックが解除されて、LTEインジケーターが緑点灯に切り替わります。

なぜデジタル庁が国内ではなく米企業のシステムを導入するのか?

「なぜデジタル庁が国内ではなく米企業のシステムを導入するのか?」その答えはシンプルだ。既に国内ITベンダーは本格的なクラウドを運用できるだけの技術力を失っているからだ。

クラウドサービスの運用には高い技術力を要求される。10台の物理サーバーで構成されるシステムの複雑さを10とするなら、単純に考えても10台の物理サーバーで動作する10インスタンスの仮想サーバーの複雑さは100になる。物理層の上に、仮想化した物理層を動作させて、大規模なクラウドを運用しようとするなら、ハードウェアからOSやアプリケーションまで垂直統合したIT技術を求められる。これらを提供できるだけのIT技術を持つ企業は、日本国内には富士通とNECの二社程度しかみあたらない。そして富士通は既にクラウド事業から撤退を決め、NECはクラウド事業に参入すらしていない。

「さくらのクラウド」や「GMOクラウド」などクラウドを提供している事業者は何社か残っているが、それらは基本的な仮想サーバーを提供するに過ぎない。大手クラウドベンダーが200種にものぼるクラウドサービスを提供している事と比較してあまりにもつたない。そこには10年以上の技術差が存在している。

海外クラウドベンダーの力を借りなければ、最新のIT技術を活用する事すらままならないのが、デジタル敗戦国などと揶揄される国内IT産業の現実だ。

ちなみに「データが丸見え」というのは、あまりにもナンセンスな指摘だ。国威無い企業なら丸見えでも問題ないかといえば、そんな訳はない。またデータを見せないために求められるのは暗号技術と暗号鍵管理で、それらがしっかりしていれば「データが丸見え」などと言うことは起きない。

ただし有事に「システム障害を故意に起こされる」と言う可能性なら確かにある。これは別に何処の国のクラウドサービスを使おうが関係なく存在するリスクだ。これに対して米国政府の場合にはFedRAMP等の、民間向けクラウドサービスよりもさらに厳格なセキュリティ要件を満たす事を求めている。日本のガバメントクラウドのセキュリティ要件は知らないが、恐らくは同じレベルのものを要求するはずだ。そうしないと米国政府とシステムを接続出来ないからね。

選挙や投票へのインターネット活用・・・ちょっと拙速じゃない?

茨城・つくば市、県立校でネット投票

高校の生徒会レベルで行うのは許容範囲だが、公共性の高い用途で使うのなら、十分な議論が必要だ。インターネットを使った選挙活動と、インターネットを使った投票の間には大きな谷があるのです。

紙による選挙では以下の様な事柄が守られています。
・匿名であること。誰が誰に投票したのか、誰にも分かりません。
・強要されないこと。選挙会場で衆人監視の元で投票するので、誰かに強要されることはありません。
・重複投票できないこと。選挙管理人監視の下で本人確認を行い、既に投票を行ったか管理しているため、重複投票は困難です。
・検証可能なこと。後日に再集計するなど、選挙結果を検証可能です。

実はインターネット投票では「匿名であること。」と「検証可能なこと。」を両立することが極めて困難なのです。また「強要されないこと。」を保証する事も難しくなります。ここがインターネット投票を行っている国家が少ない所以です。

一人の方が複数回投票したりといった事を防いだり、あるいは漏洩したユーザーアカウントを使った成り済ましを防ぐには、誰が、何時、何処から、誰に投票したかといった情報を記録せざる得ません。厳重に管理するにせよ、暗号化するにせよ、システムを管理する立場にある人には、誰が誰に投票したか分かってしまいますし、第三者に情報漏洩するリスクもあります。誰に投票しかという記録を残さず、集計結果だけを記録すれば匿名性を保持できます。ですが、その場合には後から検証する事も出来ませんし、何者かが選挙結果を改竄したばあいに検証できなくなります。

例えば電子政府で有名なエストニアではブロックチェーンを活用したインターネット投票システムを運用しています。投票内容を何度でも変更可能で、仮に強要されたとしても、後日に変更可能とすることで強要できないことを担保しているわけです。そして後日に変更可能と言うことは、投票内容は個人に紐付けられており、誰が誰に都票したかも記録されている事になります。

「インターネット投票にする」と言うことは、いままでは匿名投票だったものを、記名投票に変更するという事になります。ここは十分な議論と、周知が必要なところです。

私的にはインターネットを活用した選挙活動と一緒に、インターネットを活用した投票も早く実現して欲しいところですけどね。

「COBOL」プログラムが古くなっても動き続ける“切実な理由”

「COBOL」プログラムが古くなっても動き続ける“切実な理由”

理由と断りつつ、理由に一切触れていない辺りが、多分一番切実な理由なのだ。

COBOL言語で開発されたシステムの特徴を上げてみましょう。

・データに関する設計思想の違い
COBOLシステムと現行の一般的なデータベースとでは大きく設計思想が異なる。OBOLのデータベースは転記を繰り返しながら必要なデータを作成する。対して現行のシステムではデータ正規化を行い重複するデータを排除して管理しやすいようにする。

・可用性や信頼性に関する設計思想の違い
当時のコンピューターシステムはハードウェアで可用性と信頼性を高めるように設計されている。現行のシステムの多くはハードウェアは不定期に故障する事を前提にソフトウェアにて可用性や信頼性を高めるように設計されている。

・言語習熟の困難さ
COBOLの言語仕様自体はシンプルです。ですが実際のプログラムは各ベンダーが提供するミドルウェア上に構築されています。ミドルウェア部分は各ベンダーに依存しているため、これに習熟するためには実機での学習が必要です。ですが新たに実機を入手する事は困難です。そのためにCOBOLに習熟したエンジニアを新たに採用するのは難しくなります。

それらの理由により、COBOLで作成されたシステムを別の言語に移行しようとすると、人員が不足している状態で、現行システムを調査して仕様を調べ、全てを再設計する事を余儀なくされる事にります。リスクが大きくなりすぎて、業務上許容出来るリスクの上限を超えてしまうため、移行出来なくなるわけです。

かといって、このまま何もしなければハードウェアの老朽化によりシステムが停止するリスクが上がり続けます。許容出来るリスクにおさめるために、どんなに高価でもハードウェアを更新して、延命をはかるしかありません。

本来ならシステム移行に伴うリスクが許容出来なくなるほど大きくなる前に移行を進めるべきでした。高価な専用ハードウェアの更新や、COBOL資産を残したままのシステム移行によって延命してる話しが増えていますが、それでもリスクは少しづつ増大しているはずです。何処かでリスクを精算する事は考え続けなくてはなりません。

Power Autoamte Desktopを導入

遅ればせながらPower Automate Desktop(以下PAD)を導入。

以前はPowershell + UIAutomation.dllでデスクトップアプリケーションの自動化を行っていた。同じ処理をPADで再実装してみたが、実装にかかる作業時間が1/5程度になっている感じでありがたい。Powershell + UIAutomation.dllで記述したときには画面が表示されるのを待つためのループ処理やディレイ処理が多く遅かったのだが、PADで記述したことでディレイ処理は1箇所のみに減り、大幅に早くなっている。

ただしいくつか気になる点もある。

1.複数のMicrosoftアカウントをWindowsに関連付けていると動作しない。実行時例外が発生して「The cache contains multiple tokens satisfying the requirements. Try to clear token cache.」となってしまう。あまり使わない方のMicrosoftアカウントの連携を解除して解決した。

2.圧縮→ZIPファイルが日本語ファイル名に対応しておらず、文字化けしてしまう。OSSのUnZip(http://infozip.sourceforge.net/UnZip.html)を子プロセスとして呼ぶことで対応した。

3.コードの見にくさ。WEB上のMicrosoft Flowも何度か使ってみた事はあるのだが、一画面に20ステップ程度しか表示出来ないので、やはり複雑な処理は書きにくい。

4.バグを見つけたのでレポートしたいが、お手軽なバグレポートツールが見当たらない。ヘルプ辺りにレポートメニューがあると有り難いのだが。

総じてデスクトップアプリの自動化を行うツールとして、無償でここまで扱いやすいツールは他に無く、とてもよいと思う。だがWEBアプリ操作やファイル処理を行おうとすると、なかなか厳しい。その辺りは適材適所、SeleniumやVBAを併用する事は続きそうだ。