質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Amazon RDS

Amazon RDSは、米アマゾン社が提供しているRDBMSサービス。クラウド上でのリレーショナルデータベースの構築および運用が可能です。MySQL/PostgreSQL/Oracle/SQL Serverのインストールを容易にすることができます。

AWS Lambda

AWS Lambdaは、クラウド上でアプリを実行できるコンピューティングサービス。サーバーのプロビジョニングや管理を要せず複数のイベントに対してコードを実行します。カスタムロジック用いた他AWSサービスの拡張やAWSの規模やパフォーマンスを用いたバックエンドサービスを作成できます。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

proxy

proxy(プロキシー)は、企業などの内部コンピュータとインターネットの中間に位置し、例えば直接インターネットに接続できない内部コンピュータの代理としてインターネットに接続する等をするシステム、もしくは代理として機能を実行するソフトウェアです。内部ネットワークへのアクセスを一元管理し、内部からの特定の種類の接続以外を遮断すること、外部からの不正アクセスを拒否することなどに用いられます。

Q&A

解決済

1回答

1623閲覧

RustでAWS LambdaからRDS Proxyに接続したいがSecrets Managerの情報を取得できず、MySQLにアクセスできない問題を解消したい

akira_kano1101

総合スコア25

Amazon RDS

Amazon RDSは、米アマゾン社が提供しているRDBMSサービス。クラウド上でのリレーショナルデータベースの構築および運用が可能です。MySQL/PostgreSQL/Oracle/SQL Serverのインストールを容易にすることができます。

AWS Lambda

AWS Lambdaは、クラウド上でアプリを実行できるコンピューティングサービス。サーバーのプロビジョニングや管理を要せず複数のイベントに対してコードを実行します。カスタムロジック用いた他AWSサービスの拡張やAWSの規模やパフォーマンスを用いたバックエンドサービスを作成できます。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

proxy

proxy(プロキシー)は、企業などの内部コンピュータとインターネットの中間に位置し、例えば直接インターネットに接続できない内部コンピュータの代理としてインターネットに接続する等をするシステム、もしくは代理として機能を実行するソフトウェアです。内部ネットワークへのアクセスを一元管理し、内部からの特定の種類の接続以外を遮断すること、外部からの不正アクセスを拒否することなどに用いられます。

0グッド

1クリップ

投稿2022/10/17 09:54

編集2022/10/18 21:24

前提

Wasmでブラウザ上にて動作するアプリケーションを作りたいと思い、現在制作に取り掛かっています。

このアプリケーションのバックエンドの永続化の手段としてAWSのRDSを選択することに決めました。

使っている言語はRustで、バックエンドの構成としては大体こちら

RDS Proxy 経由で RDS に接続する

をほぼ引用するという形をとり、RDS Proxyを経由してRDSへと接続しようと考えています。

実現したいこと

curlやreqwestクレート等を用いてAPI Gatewayを通じてAWS Lambdaをキックし、RDS ProxyさらにはRDSへと接続するバックエンドを作成したいです。

当面の目標としては、RDS Proxyの画面にアクセスして確認できるQueryRequestsのグラフにアクセス履歴が表示されていない状態ですので、これを表示されるようにすることです。

なお、RDSはMySQLを利用しようと思っていて、Rust側としてはsqlxクレートを使おうと考えています。

発生している問題・エラーメッセージ

エラーメッセージではなくログになりますが、下記の該当ソースコードをAWSにアップロードしブラウザ上でテストを実行したときに出力されるログを掲載させていただきます。

補足として

AWS Secrets Managerに作成したシークレットの名前は"SecretsManager"です。

Lambda関数の名前は"Test_Function_02"です。

リージョンは"ap-northeast-3"です。

一部情報は念のため"x"で伏せています。

改行がないため少し見づらいですが、そのままを掲載する方が良いと思ったのでご容赦をお願いいたします。

START RequestId: 41e749a7-dc70-4118-9610-13fde7eaxxxx Version: $LATEST 2022-10-17T08:49:28.071756Z INFO lambda_function_01: region="ap-northeast-3" 2022-10-17T08:49:28.271553Z INFO lambda_function_01: get_secret_value_string="GetSecretValue { handle: Handle { client: Client { connector: DynConnector, middleware: DynMiddleware, retry_policy: Standard { config: Config { initial_retry_tokens: 500, retry_cost: 5, no_retry_increment: 1, timeout_retry_cost: 10, max_attempts: 3, initial_backoff: 1s, max_backoff: 20s, base: 0x5566f7xxxx }, shared_state: CrossRequestRetryState { quota_available: Mutex { data: 500, poisoned: false, .. } } }, timeout_config: Config { api: Api { call: Unset, call_attempt: Unset }, http: Http { connect: Unset, write: Unset, read: Unset, tls_negotiation: Unset }, tcp: Tcp { connect: Unset, write: Unset, read: Unset } }, sleep_impl: Some(TokioSleep) }, conf: Config }, inner: Builder { secret_id: None, version_id: None, version_stage: None } }" 2022-10-17T08:49:28.271607Z INFO lambda_function_01: secret_id_string="GetSecretValue { handle: Handle { client: Client { connector: DynConnector, middleware: DynMiddleware, retry_policy: Standard { config: Config { initial_retry_tokens: 500, retry_cost: 5, no_retry_increment: 1, timeout_retry_cost: 10, max_attempts: 3, initial_backoff: 1s, max_backoff: 20s, base: 0x5566f7xxxx }, shared_state: CrossRequestRetryState { quota_available: Mutex { data: 500, poisoned: false, .. } } }, timeout_config: Config { api: Api { call: Unset, call_attempt: Unset }, http: Http { connect: Unset, write: Unset, read: Unset, tls_negotiation: Unset }, tcp: Tcp { connect: Unset, write: Unset, read: Unset } }, sleep_impl: Some(TokioSleep) }, conf: Config }, inner: Builder { secret_id: Some(\"SecretsManager\"), version_id: None, version_stage: None } }" 2022-10-17T08:49:28.365589Z INFO lambda_function_01: sent_string="Err(ServiceError { err: GetSecretValueError { kind: Unhandled(Error { code: Some(\"AccessDeniedException\"), message: Some(\"User: arn:aws:sts::67913522xxxx:assumed-role/Test_Function_02-role-lip4xxxx/Test_Function_02 is not authorized to perform: secretsmanager:GetSecretValue on resource: SecretsManager because no identity-based policy allows the secretsmanager:GetSecretValue action\"), request_id: Some(\"bb4d7bc5-f651-49ec-9b20-7d6eb371xxxx\"), extras: {} }), meta: Error { code: Some(\"AccessDeniedException\"), message: Some(\"User: arn:aws:sts::67913522xxxx:assumed-role/Test_Function_02-role-lip4xxxx/Test_Function_02 is not authorized to perform: secretsmanager:GetSecretValue on resource: SecretsManager because no identity-based policy allows the secretsmanager:GetSecretValue action\"), request_id: Some(\"bb4d7bc5-f651-49ec-9b20-7d6eb371xxxx\"), extras: {} } }, raw: Response { inner: Response { status: 400, version: HTTP/1.1, headers: {\"x-amzn-requestid\": \"bb4d7bc5-f651-49ec-9b20-7d6eb371xxxx\", \"content-type\": \"application/x-amz-json-1.1\", \"content-length\": \"308\", \"date\": \"Mon, 17 Oct 2022 08:49:28 GMT\", \"connection\": \"close\"}, body: SdkBody { inner: Once(Some(b\"{\\\"__type\\\":\\\"AccessDeniedException\\\",\\\"Message\\\":\\\"User: arn:aws:sts::67913522xxxx:assumed-role/Test_Function_02-role-lip4xxxx/Test_Function_02 is not authorized to perform: secretsmanager:GetSecretValue on resource: SecretsManager because no identity-based policy allows the secretsmanager:GetSecretValue action\\\"}\")), retryable: true } }, properties: SharedPropertyBag(Mutex { data: PropertyBag, poisoned: false, .. }) } })" 2022-10-17T08:49:28.365643Z INFO lambda_function_01: value_string="\"No value!\"" END RequestId: 41e749a7-dc70-4118-9610-13fde7eaxxxx REPORT RequestId: 41e749a7-dc70-4118-9610-13fde7eaxxxx Duration: 599.81 ms Billed Duration: 635 ms Memory Size: 128 MB Max Memory Used: 25 MB Init Duration: 35.15 ms

該当のソースコード

toml

1[package] 2name = "lambda_function_01" 3version = "0.1.0" 4edition = "2021" 5 6[dependencies] 7aws-config = "0.49.0" 8aws-sdk-secretsmanager = "0.19.0" 9lambda_runtime = "0.7.0" 10serde_json = "1.0.86" 11sqlx = { version = "0.6.2", features = ["runtime-tokio-rustls", "mysql"] } 12tokio = { version = "1.21.2", features = ["full"] } 13tracing = { version = "0.1", features = ["log"] } 14tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }

rust

1use aws_config::meta::region::RegionProviderChain; 2use aws_sdk_secretsmanager::{output::GetSecretValueOutput, Client}; 3use lambda_runtime::{service_fn, Error, LambdaEvent}; 4use serde_json::{json, Value}; 5use tracing::info; 6use tracing_subscriber; 7 8#[tokio::main] 9async fn main() -> Result<(), Error> { 10 let func = service_fn(func); 11 lambda_runtime::run(func).await?; 12 Ok(()) 13} 14 15async fn func(_event: LambdaEvent<Value>) -> Result<Value, Error> { 16 tracing_subscriber::fmt::init(); 17 18 let region_provider = RegionProviderChain::default_provider().or_else("ap-northeast-3"); 19 20 let region = region_provider.region().await.unwrap().as_ref().to_string(); 21 info!(region); 22 23 let shared_config = aws_config::from_env().region(region_provider).load().await; 24 let client = Client::new(&shared_config); 25 26 let get_secret_value = client.get_secret_value(); 27 let get_secret_value_string = format!("{:?}", get_secret_value); 28 info!(get_secret_value_string); 29 30 let secret_id = get_secret_value.secret_id("SecretsManager"); 31 let secret_id_string = format!("{:?}", secret_id); 32 info!(secret_id_string); 33 34 let sent = secret_id.send().await; 35 let sent_string = format!("{:?}", sent); 36 info!(sent_string); 37 38 let resp = sent.unwrap_or(GetSecretValueOutput::builder().build()); 39 40 let value = resp.secret_string().unwrap_or("No value!").to_string(); 41 let value_string = format!("{:?}", value); 42 info!(value_string); 43 44 // ...上記でSecrets情報ができるはずなのでこれを使いRDS Proxyを通してRDSに接続したい... 45 // しかしエラーが発生してしまうので秘密情報を取得できない 46 47 let host: &str = &secret_info["host_proxy"].as_str().unwrap(); 48 let username: &str = &secret_info["username"].as_str().unwrap(); 49 let password: &str = &secret_info["password"].as_str().unwrap(); 50 let database: &str = &secret_info["dbname"].as_str().unwrap(); 51 52 let url = format!("mysql://{}:{}@{}/{}", username, password, host, database); 53 54 let pool = sqlx::mysql::MySqlPoolOptions::new() 55 .max_connections(5) 56 .connect(&url) 57 .await; 58 let pool_string = format!("{:?}", pool); 59 info!(pool_string); 60 61 Ok(json!({ 62 "statusCode": 200, 63 "headers": { "content-type": "application/json" }, 64 "body": "Hello world!", 65 })) 66}

出力結果

なお、テストの実行結果として以下のように動作をしています。

{ "body": "Hello world!", "headers": { "content-type": "application/json" }, "statusCode": 200 }

実施手順としては

% cargo lambda build --release --arm64 --output-format zip

で生成されたbootstrap.zipを直接ブラウザからアップロードし、ブラウザ上にあるテストタブに切り替えてテストボタンを押下して実施しています。

補足

ちなみにベタがきの部分は冒頭の引用サイトの内容を参考にして実行を試みました。

伏せておいた情報としては、パスワードにはSecretsManagerのパスワードを使い、ホストにはRDS Proxyのエンドポイントを使い接続を試しています。

さいごに

どうぞ、お分かりの方がいらっしゃいましたらご教示のほどよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

私自身はAWS Secrets ManagerもAmazon RDSも使ったことがないのでよくわからないのですが、とりあえず気づいた点について説明します。

rust

1 // ...上記でSecrets情報ができるはずなのでこれを使いRDS Proxyを通してRDSに接続したい... 2 // しかしエラーが発生してしまうので秘密情報を取得できない

ログに以下のエラーが出ていますので、Lamda関数の権限の問題のようです。

AccessDeniedException
User: arn:aws:sts::67913522xxxx:assumed-role/Test_Function_02-role-lip4xxxx/Test_Function_02 is not authorized to perform: secretsmanager:GetSecretValue on resource: SecretsManager because no identity-based policy allows the secretsmanager:GetSecretValue action

参考にされている記事の以下のところですが、

また、Lambda が SecretsManager にアクセスできる必要があるので、SecretsManagerReadWrite のポリシーを Lambda に付与します。

そのすぐ下にあるポリシーには、肝心なsecretsmanager関連のアクション(例:"secretsmanager:*")が含まれていないので、何か変です。SecretsManagerReadWriteポリシーの内容は以下のURLからAWSコンソールにログインすると見られるのですが、その内容とは違います。

また、SecretsManagerReadWriteポリシーの説明は以下のようになっており、Lamda関数に付与するためのものではなくて、AWSコンソールのログインに使うIAMユーザーに付与するためのものかもしれません。

Description: Provides read/write access to AWS Secrets Manager via the AWS Management Console. Note: this exludes IAM actions, so combine with IAMFullAccess if rotation configuration is required.

こちらにある別の記事を参考に、Lamda関数に権限を設定してみてください。

Lambda のロール

いつもの Lambda 向け権限の他に、AWS Secrets Manager からシークレットを取得するためのポリシーを追加します。

json

1{ 2 "Version": "2012-10-17", 3 "Statement": [ 4 { 5 "Sid": "VisualEditor0", 6 "Effect": "Allow", 7 "Action": "secretsmanager:GetSecretValue", 8 "Resource": "*" 9 } 10 ] 11}

投稿2022/10/17 11:20

tatsuya6502

総合スコア2035

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

akira_kano1101

2022/10/18 21:33 編集

tatsuya6502様 ご回答ありがとうございます。 アドバイスくださったように、ポリシーを付与することでエラーとなっていた秘密情報をログで確認することができました。 ロールとポリシーの重要性が理解でき大変助かりました。 ただ、その後のsqlxのコネクション確立の部分(本文を書き換えさせていただきますのでご確認をお願いします)でうまくいかず、実行結果がタイムアウトで失敗になってしまいます。 下記記事も参考にしながら進めてみていますが、セキュリティグループの問題なのか権限の問題なのかタイムアウトになる原因がわからずにいます。 https://aws.amazon.com/jp/blogs/news/using-amazon-rds-proxy-with-aws-lambda/ https://qiita.com/k-sasaki-hisys-biz/items/12f680f9a97998322cc0 Proxyに設定すべき何らかの情報が欠落しているためうまくいかないと踏んでいるのですが、何が原因でしょうか? もう少しだけ、ご助力ください。よろしくお願いいたします。 追記: 色々と触ってみるとタイムアウトは起こらなくなりました。 触りすぎたので理由がはっきりしないですがターゲットグループが利用可能ではなかったかもしれません。 ただエラーメッセージに次のように表示されます。 2022-10-18T21:06:34.840208Z INFO lambda_function_01: pool_string="Err(Database(MySqlDatabaseError { code: Some(\"28000\"), number: 1045, message: \"Access denied for user 'admin'@'xxx.xxx.xxx.xxx' (using password: YES)\" }))" 現在調べているのですが、こちらに次の場合について書かれていました。 https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/rds-proxy.troubleshooting.html > ERROR 1045 (28000): Access denied for user 'DB_USER'@'%' (using password: YES) 少し試してみようと思います。 追記2: 解決しました。 シークレットの値にhost_proxyというキー名でproxy-05.proxy-xxxxxxxxxxxx.ap-northeast-3.rds.amazonaws.comとしてRDS Proxyのホスト名を追加しました。(その後シークレットから取らずベタがきにすると動いてしまいましたが) 本文を書き換えさせていただきますが、これでRDS Proxyにアクセスでき、QueryRequestsのグラフも動作するようになりました。 結局何が原因かわからなくなってしまいましたが、ひとまず動作しました。 あとでもう一回作り直そうと思います。 重ねて感謝いたします。ありがとうございました。
tatsuya6502

2022/10/19 03:30

解決してよかったです! タイムアウトのところはネットワークの疎通ができてなかったように見えた(RDS Proxy側にアクセス履歴が表示されない。RDS Proxyからのレスポンスがない)ので、セキュリティグループの設定が一番怪しかった感じがします。その次に怪しかったのは、VPCの設定かな。
akira_kano1101

2022/10/19 21:24

はい! わかりました、参考にしたいと思います。 いつもありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問