# How to ガイド - AWS サービスの認証

AWS サービスは2通りの方法で認証できます。Workato では、AWS V4 署名の生成を支援して認証プロセスを簡素化する AWS ライブラリをサポートしています。ユーザーはこれにより、アクションとトリガーの作成に集中できるようになります。

このガイドでは、以下の両方のデュアル認証を実装する方法について説明します。

  1. アクセスキー認証 (opens new window)
  2. AWS セキュリティトークンサービスを通じた IAM ロール認証 (opens new window)

注意

AWS と Workato はどちらも AWS IAM ロール認証の使用を推奨しています。Workato では、これをコネクターのユーザーのデフォルト認証メソッドにすることを推奨しています。

# サンプルコネクター - 一般的なコネクター

{
  title: "Sample AWS S3 Connector",

  connection: {
    fields: [
      {
        name: "aws_auth_type",
        label: "AWS Authorization type",
        control_type: "select",
        optional: false,
        pick_list: [
          ["IAM role", "aws_role_based"],
          ["Access key", "aws_key_secret"]
        ],
        default: "aws_role_based",
        hint: 'Learn more about Amazon S3 authorization support <a href="http://docs.workato.com/connectors/s3.html#how-to-connect-to-amazon-s3-on-workato" target="_blank">here</a>.'
      },
      {
        name: "aws_assume_role",
        label: "IAM role ARN",
        optional: false,
        ngIf: 'input.aws_auth_type == "aws_role_based"',
        help: {
          title: "Using IAM Role authorization",
          text: <<~HELP
            Create an IAM role in your AWS account using the following data:
            <br/>&nbsp;- Use Workato AWS Account ID <b>{{ authUser.aws_iam_external_id }}</b>
            to generate the <b>Principal</b> for the role.
            <br/>&nbsp;- Use <b>{{ authUser.aws_workato_account_id }}</b> as the <b>External ID</b> for the role.
            <br/>&nbsp;- Set this field's value to the newly created role's ARN.
            <br/><a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user.html"
            target="_blank">Learn more</a>.
          HELP
        }
      },
      {
        name: "aws_api_key",
        label: "Access key ID",
        control_type: "password",
        optional: false,
        hint: "Go to <b>AWS account name</b> > <b>My Security Credentials</b> > <b>Users</b>. Get API key from existing user or create new user.",
        ngIf: 'input.aws_auth_type == "aws_key_secret"'
      },
      {
        name: "aws_secret_key",
        label: "Secret access key",
        control_type: "password",
        optional: false,
        hint: "Go to <b>AWS account name</b> > <b>My Security Credentials</b> > <b>Users</b>. Get secret key from existing user or create new user.",
        ngIf: 'input.aws_auth_type == "aws_key_secret"'
      },
      {
        name: "aws_region",
        optional: false,
        hint: "AWS service region. If your account URL is <b>https://eu-west-1.console.s3.amazon.com</b>, use <b>eu-west-1</b> as the region."
      }
    ],

    authorization: {
      type: "custom_auth"
    }
  },

  test: lambda do |connection|
    call(:list_buckets, connection)
  end,

   methods: {
    list_buckets: lambda do |connection|
      signature = aws.generate_signature(
        # The connection object defined earlier. 
        connection: connection, 
        # The internal name of the AWS service you are targeting
        service: "s3", 
        # The AWS service region you are targeting. 
        # For services with a globally unique endpoint such as IAM, use us-east-1.
        region: connection["aws_region"], 
        # The host of the API url. 
        # Optional and defaults to "#{service}.#{region}.amazonaws.com".
        # In some cases like AWS API Gateway and AWS IAM, your host may not follow this standard and require you to override the host. 
        host: "s3.dualstack.#{connection['aws_region']}.amazonaws.com", 
        # The relative path of the endpoint. Optional and defaults to "/"
        path: "/", 
        # The verb used for the request. Optional and defaults to "GET"
        method: "GET", 
        # The query parameters for the request. Optional and defaults to {}
        params: { "list-type" => 2, "max-keys" => 1000 }, 
        # The headers for the request. Optional and defaults to {}
        headers: {},
        # The payload for the request. Optional and defaults to "" 
        payload: ""
      )
      url = signature[:url]
      headers = signature[:headers]

      response = get(url).headers(headers).response_format_xml

      files = response.dig("ListBucketResult", 0, "Contents")
      files = Array.wrap(files).map do |content|
        content.each_with_object({}) do |(k, v), obj| 
          obj[k] = Array.wrap(v).dig(0, "content!")
        end
      end

      { "files" => files }
    end
  }
}

# ステップ1 - 接続項目の定義

connection キーの中の fields キー内で、入力項目を定義します。この定義は、ハッシュからなる配列で行われます。その配列内のハッシュは、それぞれが1つの入力項目を表現します。定義内では、入力項目の名前や、エンドユーザーに表示されるヒントといったパラメータを宣言できます。この例では、ユーザーが認証を行うための方法を2つ提示しています。そのどちらが選ばれるかは、aws_auth_type 項目の入力で決定されます。

その選択に基づいて、この例では以降の aws_assume_role、または aws_api_key および aws_secret_key の項目を選択的に表示 / 非表示にしています。これは ngIf 属性を利用して実行されます。

TIP

幸いなことに、ほとんどの AWS サービスは同様の認証方法を利用しているため、コピーして貼り付けるだけで、上記の例と同じコネクション項目を利用できます。

さらに項目を追加する場合、少なくとも name キーは指定する必要があります。さらに optionalhintcontrol_type といった追加的な属性があれば、その項目の別の要素をカスタマイズできます。クライアントシークレットのような機密情報に対しては、必ず control_typepassword として使用してください。

Workato で入力項目を定義する方法については、こちらを参照してください。

# ステップ2 - AWS 署名の生成

他の認証方法とは異なり、AWS では現在の時刻が署名のコンポーネントとなっており、それぞれのリクエストごとに一意の署名が必要となります。したがって、一般的に適用できる資格情報が存在しないため、コネクターでは apply の lambda 関数を使用しないでください。

その代わりに、API コールを行う前に aws.generate_signature メソッドを使用して有効な URL と署名を取得する必要があります。この例では、S3 に GET リクエストを行うメソッド list_buckets を作成しています。

    list_buckets: lambda do |connection|
      signature = aws.generate_signature(
        # The connection object defined earlier. 
        connection: connection, 
        # The internal name of the AWS service you are targeting
        service: "s3", 
        # The AWS service region you are targeting. 
        # For services with a globally unique endpoint such as IAM, use us-east-1.
        region: connection["aws_region"], 
        # The host of the API url. 
        # Optional and defaults to "#{service}.#{region}.amazonaws.com".
        # In some cases like AWS API Gateway and AWS IAM, your host may not follow this standard and require you to override the host. 
        host: "s3.dualstack.#{connection['aws_region']}.amazonaws.com", 
        # The relative path of the endpoint. Optional and defaults to "/"
        path: "/", 
        # The verb used for the request. Optional and defaults to "GET"
        method: "GET", 
        # The query parameters for the request. Optional and defaults to {}
        params: { "list-type" => 2, "max-keys" => 1000 }, 
        # The headers for the request. Optional and defaults to {}
        headers: {},
        # The payload for the request. Optional and defaults to "" 
        payload: ""
      )
      url = signature[:url]
      headers = signature[:headers]

      response = get(url).headers(headers).response_format_xml

      files = response.dig("ListBucketResult", 0, "Contents")
      files = Array.wrap(files).map do |content|
        content.each_with_object({}) do |(k, v), obj| 
          obj[k] = Array.wrap(v).dig(0, "content!")
        end
      end

      { "files" => files }
    end

# ステップ3 - コネクションのテスト

メソッドの定義を済ませたので、テストでそのメソッドを呼び出し、ユーザーの資格情報を検証することができます。

  test: lambda do |connection|
    call(:list_buckets, connection)
  end,

# トラブルシューティングのヒント

AWS 署名が正しいことを、コネクションのテストによって検証するのは難しいことかもしれません。推奨される方法は、(上記の例で行ったように) メソッド内で簡単な API リクエストをラップし、手始めにコネクションのスタブを作成することです。これによりアクションをテストできるようになります。

{
  title: "Sample AWS S3 Connector",

  connection: {
    fields: [
      #  Same fields as earlier
    ],

    authorization: {
      type: "custom_auth"
    }
  },

  test: lambda do |connection|
    true
  end,

  actions: {
    sample_action: {
      execute: lambda do |connection|
        call(:list_buckets, connection)
      end
    }
  },

  methods: {
    list_buckets: lambda do |connection|
      # Method from earlier
    end
  }
}

sample_action アクションをテストすることで、Workato SDK フレームワークまたは接続先となる AWS API で生じたエラーのデバッグに関するより良い洞察が得られるでしょう。

# コネクションの SDK リファレンス

connection キー内で使用可能なキーの詳細は、SDK リファレンスを参照してください。


Last updated: 2023/8/31 1:07:14