32

短いバージョン: Python を使用して Amazon CloudFront/S3 で Nginx の X-Accel-Redirect 動作 (つまり、ダウンロードの保護) を模倣するために、署名付き URL を「オンデマンド」で作成するにはどうすればよいですか。

NginxフロントエンドでDjangoサーバーを稼働させています。私はそれへの要求に打ちのめされており、最近、FastCGI モードでのクラッシュを防ぐためにTornado WSGI アプリケーションとしてインストールする必要がありました。

現在、サーバーに対するメディアのリクエストが多すぎるため、サーバーが動かなくなる (つまり、帯域幅のほとんどが使い果たされる) という問題が発生しています。CDN を調べていて、Amazon CloudFront/S3 だと思います私にとって適切な解決策になります。

ファイルを不正なダウンロードから保護するために Nginx の X-Accel-Redirect ヘッダーを使用してきましたが、CloudFront/S3 にはその機能がありませんが、署名付き URL は提供しています。私はPythonの専門家ではなく、署名付きURLを適切に作成する方法をまったく知らないので、誰かがこれらのURLを「オンデマンド」にする方法のリンクを持っているか、方法を喜んで説明してくれることを望んでいました.ここで、それは大歓迎です。

また、これは適切な解決策ですか?私は CDN にあまり詳しくありません。これに適した CDN はありますか?

4

6 に答える 6

36

Amazon CloudFrontの署名付きURLは、AmazonS3の署名付きURLとは動作が異なります。CloudFrontは、Amazonアカウントクレデンシャルページで設定する必要がある個別のCloudFrontキーペアに基づくRSAシグネチャを使用します。M2Cryptoライブラリを使用してPythonで時間制限付きURLを実際に生成するコードを次に示します。

CloudFrontのキーペアを作成する

これを行う唯一の方法は、AmazonのWebサイトを使用することだと思います。AWSの[アカウント]ページに移動し、[セキュリティクレデンシャル]リンクをクリックします。[キーペア]タブをクリックしてから、[新しいキーペアの作成]をクリックします。これにより、新しいキーペアが生成され、秘密キーファイル(pk-xxxxxxxxx.pem)が自動的にダウンロードされます。キーファイルを安全かつプライベートに保ちます。また、次のステップで必要になるため、Amazonの「キーペアID」を書き留めておきます。

PythonでいくつかのURLを生成する

botoバージョン2.0の時点では、署名されたCloudFrontURLの生成はサポートされていないようです。Pythonには標準ライブラリにRSA暗号化ルーチンが含まれていないため、追加のライブラリを使用する必要があります。この例ではM2Cryptoを使用しました。

非ストリーミングディストリビューションの場合、リソースとして完全なクラウドフロントURLを使用する必要がありますが、ストリーミングの場合、ビデオファイルのオブジェクト名のみを使用します。5分間しか持続しないURLを生成する完全な例については、以下のコードを参照してください。

このコードは、AmazonがCloudFrontドキュメントで提供しているPHPサンプルコードに大まかに基づいています。

from M2Crypto import EVP
import base64
import time

def aws_url_base64_encode(msg):
    msg_base64 = base64.b64encode(msg)
    msg_base64 = msg_base64.replace('+', '-')
    msg_base64 = msg_base64.replace('=', '_')
    msg_base64 = msg_base64.replace('/', '~')
    return msg_base64

def sign_string(message, priv_key_string):
    key = EVP.load_key_string(priv_key_string)
    key.reset_context(md='sha1')
    key.sign_init()
    key.sign_update(message)
    signature = key.sign_final()
    return signature

def create_url(url, encoded_signature, key_pair_id, expires):
    signed_url = "%(url)s?Expires=%(expires)s&Signature=%(encoded_signature)s&Key-Pair-Id=%(key_pair_id)s" % {
            'url':url,
            'expires':expires,
            'encoded_signature':encoded_signature,
            'key_pair_id':key_pair_id,
            }
    return signed_url

def get_canned_policy_url(url, priv_key_string, key_pair_id, expires):
    #we manually construct this policy string to ensure formatting matches signature
    canned_policy = '{"Statement":[{"Resource":"%(url)s","Condition":{"DateLessThan":{"AWS:EpochTime":%(expires)s}}}]}' % {'url':url, 'expires':expires}

    #sign the non-encoded policy
    signature = sign_string(canned_policy, priv_key_string)
    #now base64 encode the signature (URL safe as well)
    encoded_signature = aws_url_base64_encode(signature)

    #combine these into a full url
    signed_url = create_url(url, encoded_signature, key_pair_id, expires);

    return signed_url

def encode_query_param(resource):
    enc = resource
    enc = enc.replace('?', '%3F')
    enc = enc.replace('=', '%3D')
    enc = enc.replace('&', '%26')
    return enc


#Set parameters for URL
key_pair_id = "APKAIAZVIO4BQ" #from the AWS accounts CloudFront tab
priv_key_file = "cloudfront-pk.pem" #your private keypair file
# Use the FULL URL for non-streaming:
resource = "http://34254534.cloudfront.net/video.mp4"
#resource = 'video.mp4' #your resource (just object name for streaming videos)
expires = int(time.time()) + 300 #5 min

#Create the signed URL
priv_key_string = open(priv_key_file).read()
signed_url = get_canned_policy_url(resource, priv_key_string, key_pair_id, expires)

print(signed_url)

#Flash player doesn't like query params so encode them if you're using a streaming distribution
#enc_url = encode_query_param(signed_url)
#print(enc_url)

キーペアを保持しているアカウント(または、自分のアカウントの場合は「Self」)にTrustedSignersパラメーターを設定してディストリビューションを設定してください。

Pythonを使用したスト​​リーミング用にこれを設定するための完全に機能する例については、Pythonを使用した安全なAWSCloudFrontストリーミングの開始を参照してください。

于 2011-07-08T12:30:39.627 に答える
28

この機能は、最新の公式 AWS SDK for Python である Boto3の基盤となるライブラリであるBotocore で既にサポートされています。(次のサンプルでは rsa パッケージのインストールが必要ですが、他の RSA パッケージも使用できます。独自の「正規化された RSA 署名者」を定義するだけです。)

使用法は次のようになります。

    from botocore.signers import CloudFrontSigner
    # First you create a cloudfront signer based on a normalized RSA signer::
    import rsa
    def rsa_signer(message):
        private_key = open('private_key.pem', 'r').read()
        return rsa.sign(
            message,
            rsa.PrivateKey.load_pkcs1(private_key.encode('utf8')),
            'SHA-1')  # CloudFront requires SHA-1 hash
    cf_signer = CloudFrontSigner(key_id, rsa_signer)

    # To sign with a canned policy::
    signed_url = cf_signer.generate_presigned_url(
        url, date_less_than=datetime(2015, 12, 1))

    # To sign with a custom policy::
    signed_url = cf_signer.generate_presigned_url(url, policy=my_policy)

免責事項: 私はその PR の作成者です。

于 2015-12-16T22:01:30.580 に答える
15

多くの人がすでにコメントしているように、最初に受け入れられた回答は実際にはAmazon CloudFrontには当てはまりません。CloudFront介してプライベート コンテンツを提供するには、専用のCloudFront 署名付き URLを使用する必要があります。時間がかかり、CloudFront の署名付き URL を生成するためのサポートが追加されました(これに感謝します!)。

botoは専用のcreate_signed_urlメソッドをサポートするようになり、以前のバイナリ依存関係である M2Crypto も最近、純粋な Python RSA 実装に置き換えられました。 「クラウドフロントの URL 署名に M2Crypto を使用しない」を参照してください。

ますます一般的になってきているように、関連する単体テスト ( test_signed_urls.py を参照) 内で 1 つまたは複数の適切な使用例見つけることができます。キー):self.pk_idself.pk_str

def test_canned_policy(self):
    """
    Generate signed url from the Example Canned Policy in Amazon's
    documentation.
    """
    url = "http://d604721fxaaqy9.cloudfront.net/horizon.jpg?large=yes&license=yes"
    expire_time = 1258237200
    expected_url = "http://example.com/" # replaced for brevity
    signed_url = self.dist.create_signed_url(
        url, self.pk_id, expire_time, private_key_string=self.pk_str)
    # self.assertEqual(expected_url, signed_url)
于 2013-04-22T11:04:55.100 に答える
0

s3.generate_urlシンプルな解決策は方法を変える必要がないことがわかりました。

Cloudfront config: を選択するだけですYes, Update bucket policy

からの変更後:

https://xxxx.s3.amazonaws.com/hello.png&Signature=sss&Expires=1585008320&AWSAccessKeyId=kkk

https://yyy.cloudfront.net/hello.png&Signature=sss&Expires=1585008320&AWSAccessKeyId=kkk

yyy.cloudfront.netCloudFront ドメインです

参照: https://aws.amazon.com/blogs/developer/accessing-private-content-in-amazon-cloudfront/

ここに画像の説明を入力

于 2020-03-23T07:16:25.537 に答える