Cloudinary におけるアクセス制限の設定方法と署名付きURL

2020.08.28

Guten Morgen!ベルリンから伊藤です。

画像や動画のデジタルメディア管理・変換 SaaS、Cloudinaryを使うと、画像・動画の最適化ウォーターマークの追加が簡単に実現できます。

以前、Cloudinary でウォーターマークを簡単に付与し、URL操作によるウォーターマーク除去がされないようにするアクセス制限について解説しました。

Cloudinary におけるアクセス制限とウォーターマークの除去対策

本稿では、具体的にアクセス制限で Private/Authenticated へ設定する方法と、制限したアセットへアクセスするための署名付きURLの取得について解説します。

アセットを Private/Authenticated で格納

デフォルトでは、Cloudinaryに格納されるアセットはパブリックの状態で、アセットタイプ(画像であれば image/)の後に upload というタイプが使用され、アセットのパスとファイル名(パブリックID)が続きます。

https://res.cloudinary.com/CLOUD-NAME/image/upload/sample.jpg

この状態では誰でもアクセスすることができ、さらにはURL内に変換パラメータを追加・変更するだけで別の変換を適用させることができます。変換パラメータによる即座の変換はCloudinaryの利点ではありますが、ウォーターマークを付与した画像を配信して、勝手に変換操作でロゴのない画像を取得されては困ります。

ユースケースや使い分けの詳細は前回のブログにありますが、ここでは Private、Authenticated への設定方法を説明します。

コンソール

残念ながら、現時点でコンソールからの操作は限られており、アップロード時に都度アセットタイプを指定したり、既存アセットのタイプ設定を変更することはできません。一度アップロードしたアセットについては、タイプを変更するには、APIで変更するか、コンソールではアップロードし直す必要があります。

コンソールからアップロードする際のアセットのタイプを指定する場合、アップロードプリセットを使います。アップロードプリセットとは、アップロード設定のテンプレートのようなもので、これを使って コンソールからアップロードするすべてのアセットにタイプを指定することができます。

アップロードプリセットを作成し、Media Library のアップロードに適用させる

◆ 英語ドキュメント: How can I add upload-options when uploading via the Media-Library?

コンソールにログインして設定画面の Upload を開き、プリセットの追加に進みます。

Cloudinary - Add an upload preset

プリセットの設定画面で、Signing Mode に「Signed」(ユーザサインインした状態で使う場合)を選択し、Delivery type で選択したいタイプ「Upload」「Authenticated」「Private」のいずれかを選択します。

なお、Signing Mode「Unsigned」は、アップロードウィジェットを使って非ユーザによるアップロードを行わせる場合に指定するので、今回は使いません。

その他、格納先のフォルダ、アセットのパブリックIDにファイル名を使うかどうか、タグ付け等のオプションも適宜設定します。

Cloudinary - Configure an upload preset

プリセットを作成したら、再び設定の Upload 内、 Media library's upload presets で作成したプリセットを選択します。

Cloudinary - Set the Media Library's upload preset

これで、コンソールの Media Library からアップロードした画像はすべて、このプリセット設定を適用することになり、指定したタイプでアップロードされます。Video、Rawにもそれぞれプリセットを指定することで、同様に動画やそれ以外のアセットについてもそれぞれ指定することが可能です。

API

Upload API を使えば、タイプを指定したアップロードや変更が柔軟に行えます。ここでは、Pythonによる実行例を紹介します。

◆ 参考:PythonからCloudinaryを操作してみた | Developers.IO

アップロード時にタイプを指定する

アップロード時、typeオプションを指定するだけです。この例ではローカル画像を private としてアップロードしています。

cloudinary.uploader.upload("./cafe.png",
   public_id = "ito-test/cafe",
   type = "private")

既存アセットのタイプを変更する

タイプの変更には、Renameメソッドを使い、typeto_typeオプションを指定します。同じ名前を指定することでパブリックIDを維持することはできますが、タイプの変更によりいずれにせよ画像URLのパスが変わることにご注意ください。

この例では、タイプを authenticated から private へ変更しています。

cloudinary.uploader.rename("ito-test/cafe", "ito-test/cafe",
   type = "authenticated",
   to_type = "private")

署名付き URL の取得

署名付きURLとは s--SIGNATURE-- の形式でランダムな値が含まれるURLで、アクセス制限されたアセットを表示させるための認証として使われます。具体的には、以下のような場合に必要となります。

  • Authenticated タイプのアセットを表示させる場合
  • Private タイプのアセットのオリジナルを表示させる場合
  • Strict Transformation が有効なアカウントで許可されていない変換を適用させたアセットを表示させる場合
  • 外部のメディアからの取り込みを制限している場合

署名は Cloudinary で自動的に生成されます。生成アルゴリズムにはパブリックID、変換パラメータ、API シークレットが使われているため、同じ署名を他の変換に使い回したりすることはできません

◆ 英語ドキュメント: Signed delivery URLs

コンソール

コンソールでは、Private アセットのオリジナルURL、Authenticated アセットのすべてのURL、あるいはアカウントで Strict Transformations が有効な場合の変換URLには、自動的に署名付きURLが発行されます。

次の例は Strict Transformations が無効なアカウントの Private アセットで、オリジナルURLには署名が含まれています。

Cloudinary - Private asset on Console with signed URL

API

変換 API を使ってアセットの変換URLを取得する場合は、sign_url オプションをTrueに指定します。

cloudinary.CloudinaryImage("ito-test/cafe.jpg").image(
   height = 300,
   width = 300,
   crop = "fill",
   sign_url = True, # 署名付きURL
   type = "private", # タイプ
   secure = True # HTTPS
)
# <img height="300" src="https://res.cloudinary.com/CLOUD-NAME/image/private/s--dvvbB4Ws--/c_fill,h_300,w_300/v1/ito-test/cafe.jpg" width="300"/>

ユースケース

一度公開してアクセスされたアセットを非表示にする

パブリックに配信して、既にユーザによるアクセス済みでキャッシュされている画像についても、これをやっぱり非表示にさせたいという場合には、URL変更とキャッシュ無効化を行えばOKです。

例えば、ウェブサイト内に以下のような画像URLが埋め込まれていたとします。ウェブサイト上でこのコンテンツを取り下げたとしても、このままでは画像URLには引き続きアクセス可能です。

<img src="https://res.cloudinary.com/CLOUD-NAME/image/upload/c_fill,e_improve,f_auto,g_auto,h_600,q_auto:best,w_600/v1/ito-test/cafe.jpg" alt="Photogenic cafe" />

URLを変更する方法は、パブリックID(フォルダパスまたはファイル名)を変更するか、タイプを変更するかの2つです。どちらでも構いませんが、前者のみの場合はもし万が一、分かりやすい名前で予想されるなどURLが知れてしまったら、誰でもアセットにアクセスできてしまいます。

次の例で、フォルダパスを変更し、パブリックの画像を authenticated に切り替え、さらに invalidate オプションを有効にして既存CDNキャッシュを無効化します。これにより、キャッシュ保持期間を待たず、すぐに元のパブリックの画像URLにアクセスすることができなくなります。

cloudinary.uploader.rename("ito-test/cafe", "hide/cafe",
   type = "upload",
   to_type = "authenticated",
   invalidate = True)

※ 完全にCDN伝播させるため、キャッシュ無効化には、数分(最大1時間)かかります。
※ キャッシュの保持期間はアセットやURLの種類により異なり、デフォルトでは30日です。

◆ 参考:CDNキャッシュ保持期間 - For how long does Cloudinary cache my delivered content on the CDN?

 

authenticated アセットは、署名付きURLを発行することで引き続きアクセス可能です。

cloudinary.CloudinaryImage("hide/cafe.jpg").image(transformation=[
  { 'raw_transformation' : "c_fill,e_improve,f_auto,g_auto,h_600,q_auto:best,w_600" }
  ],
  type = "authenticated",
  sign_url = True,
  secure = True)
# '<img src="https://res.cloudinary.com/CLOUD-NAME/image/authenticated/s--Yssbotd7--/c_fill,e_improve,f_auto,g_auto,h_600,q_auto:best,w_600/v1/hide/cafe.jpg"/>'
# # ↑署名URLはアクセス可能
# # ↓正しいパブリックIDを使っても署名URLがないとアクセス不可
# # https://res.cloudinary.com/CLOUD-NAME/image/upload/c_fill,e_improve,f_auto,g_auto,h_600,q_auto:best,w_600/v1/hide/cafe.jpg

 

なお、初めからアセットのオリジナルを一時的に配信するつもりの場合には、Private アセットとして時間制限付きURLを発行することができます。こちらのブログでも最後に紹介されています。

◆ 英語ドキュメント: Providing time-limited access to private media assets

その他

署名付きURLの無効化

デフォルトでは、署名付きで配信されたURLはキャッシュ無効化させることができません。これをアカウントで有効にするには、サポートヘ問い合わせます。

◆ 参考:正しく無効化されない原因 - Why wasn't my URL properly invalidated?

Access mode 機能との違い

本稿で紹介した private、authenticated は配信タイプと称されていますが、よく似た機能でアクセスモードというものがあります。現時点でドキュメントでも同じページに掲載されており、public か authenticated から指定することができ、非常に似ています。

配信タイプでは upload、private、authenticated でそれぞれURLにも影響があるのに対し、アクセスモードではURLは upload のまま、authenticatedの機能を使うことができます。しかし、サポートに確認したところ、アクセスモードは廃止予定の機能とのことでした。

実際に、API でアップロード時の指定(以下)や更新(cloudinary.api.update_resources_access_mode, cloudinary.api.update_resources_access_mode_by_ids)を試しましたが、Python・Node.js とも、アトリビュートが存在しないといったエラーが出力されました。念のため Github からも含まれていないことを確認しました。

>>> cloudinary.uploader.upload("Pictures/stairs.png", { access_mode: "authenticated" });
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'access_mode' is not defined

なお、プリセットの設定で access mode に「Authenticated」を指定することでアップロードは可能ですが、配信タイプと同様にコンソールからは変更できず、APIもこの通り使えないので 、実質その後の設定変更ができないようでした。当然、配信タイプとも設定は異なるため、Renameメソッドを使ってみても、アクセスモードの変更はできず、重複して配信タイプの設定を持つようでした。

◆ 英語ドキュメント: Access mode

Private/Authenticated アセットのオーバーレイ

authenticated の画像変換を取得するには、当然署名付きURLが必要ですが、パブリック画像の変換でオーバーレイとして authenticated 画像を入れた場合どうなるのか?

  • authenticated アセットの変換:署名URLが必要
  • パブリックアセットの変換:署名URLが不要
  • パブリックアセットの変換(authenticatedアセットのオーバーレイ):???

ベース画像がパブリックなので、抜け穴的に署名なしでもオーバーレイなら authenticated アセットを取得できるのではないか? と思ったんですが...

# OK (パブリックアセットのみ)
https://res.cloudinary.com/CLOUD-NAME/image/upload/c_scale,w_400/v1592053931/ito-test/gallery.jpg
# NG(署名なし:authenticated アセットのオーバーレイ)
https://res.cloudinary.com/CLOUD-NAME/image/upload/c_scale,w_400/l_cm_logo/v1592053931/ito-test/gallery.jpg
# NG(署名あり:authenticated アセットのオーバーレイ)
https://res.cloudinary.com/mai-ito-test/image/upload/s--igtuFhvH--/c_scale,w_400/l_cm_logo/v1/ito-test/gallery.jpg

実際、署名ありでも authenticated アセットをオーバーレイさせた画像を取得することはできませんでした。(Privateも同様)

ということで、オーバーレイ・アンダーレイをする予定がある場合には、Cloudinary 内のアセットをやみくもにすべて private や authenticated で格納してはいけないなということが分かりました。

参考


クラスメソッドはCloudinaryのパートナーとして導入のお手伝いをさせていただいています。お気軽にこちらからお問い合わせください。こちらから無料でもサインアップいただけます。