経緯
業務でDocumentDBに触れる機会があったので書いてみます。
インフラ構築はCloud9上でTerraformを使用して行ないました。
DocumentDBはmongoDB互換DBであり、スキーマレスにデータを保存することができます。
ただいくらスキーマレスとはいえある程度の制約を持たせたいユースケースもあります。
(studentsコレクション中のドキュメントには生徒名、学年を必須にする、など)
そのような場合は以下公式ドキュメントを参考に制約を設けることができます。
https://www.mongodb.com/docs/v5.0/core/schema-validation/
業務上のユースケースにおいても制約を設けたかったので、DocumentDBの作成後にDB及びコレクションを作成し、制約を持たせる初期設定を行いました
結論
踏み台EC2を作成し、SSHトンネリング後、shファイルを実行しました。
というのも今回はVPCも新規作成して、その中にDocumentDBを作成したため、Terraformを実行しているCloud9からはDocumentDBにアクセスできなかったのです。(VPCピアリングすれば出来ると思われるが初期設定にそんなコストをかけたくない)
またStudio 3TなどのGUIツールを使用する予定だったため、どのみち踏み台サーバとSSHトンネリングは必要になるため、上記の方法を取りました。
実際のコード
VPC、DocumentDB、EC2作成のコードは割愛します。
resource "null_resource" "mongo_initial_setup" {
depends_on = [var.depends_on_db, var.depends_on_server]
provisioner "local-exec" {
environment = {
docdb_user = var.docdb_user
docdb_password = var.docdb_password
docdb_host = var.docdb_host
bastion_public_dns = var.bastion_public_dns
}
command = "~./modules/mongo/src/mongo_setup.sh"
}
}
variable depends_on_db {}
variable depends_on_server {}
variable docdb_user {}
variable docdb_password {}
variable docdb_host {}
variable "bastion_public_dns" {}
Terraformが実行されているCloud9から、踏み台サーバーを通じてDocumentDBへSSHトンネリングを行い、Mongoコマンドを流し込んでいます。
#!/bin/bash
docdb_user=$docdb_user
docdb_password=$docdb_password
docdb_host=$docdb_host
bastion_public_dns=$bastion_public_dns
wget https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem
ssh -o StrictHostKeyChecking=no -i "~./bastion_key_pair.id_rsa" -L 27017:$docdb_host:27017 ec2-user@$bastion_public_dns -N -f
mongo --tlsAllowInvalidHostnames --tls --tlsCAFile global-bundle.pem --username $docdb_user --password $docdb_password<<EOF
use my_custom_database
db.createCollection("students", {
validator: {
\$jsonSchema: {
bsonType: "object",
required: [ "name", "year", "major", "address" ],
properties: {
name: {
bsonType: "string",
description: "must be a string and is required"
},
year: {
bsonType: "int",
minimum: 2017,
maximum: 3017,
description: "must be an integer in [ 2017, 3017 ] and is required"
},
major: {
enum: [ "Math", "English", "Computer Science", "History", null ],
description: "can only be one of the enum values and is required"
},
gpa: {
bsonType: [ "double" ],
description: "must be a double if the field exists"
},
address: {
bsonType: "object",
required: [ "city" ],
properties: {
street: {
bsonType: "string",
description: "must be a string if the field exists"
},
city: {
bsonType: "string",
description: "must be a string and is required"
}
}
}
}
}
}
})
db.students.insert({ "name":"John doe", "year":NumberInt(2018), "major":"Computer Science", "gpa":3.5, "address":{ "street":"123 Main St", "city":"Anytown" } })
EOF
PORT=27017
PID=$(sudo lsof -t -i :$PORT)
sudo kill -9 $PID
echo "ポート $PORT のプロセスを終了しました。"
echo "DocumentDBの初期設定が完了しました。"
詰まった点
DocumentDBのTLSを有効化していたので、証明書の確認に手間取りました。
実際は以下のドキュメントで解決したのですが、--sslAllowInvalidHostnames
オプションをつけるのはセキュリティ的にどうなんでしょう......
https://docs.aws.amazon.com/documentdb/latest/developerguide/connect-from-outside-a-vpc.html
他にもDocumentDBに関する公式ドキュメントは、tlsが推奨されているところがsslだったり、mongoshが推奨されているところがmongoだったり、ちょこちょこレガシーな部分が見受けられます。今後変更されるんでしょうか
以上