2011 platformday 에서 mongoDB 적용 사례가 소개되면서 mongoDB 를 시작하려는 개발자분들이 많아진 듯 합니다. 그래서 mongoDB에 대한 학습을 이제 막 시작하려는 분들을 위해 mongoDB 설치 직후 확인해야 할 보안관련 내용을 공유할까 합니다.
우선 mongoDB 에 대한 간략한 소개를 하겠습니다.
mongoDB ?
스키마에 제약 없이 json 형태의 Document 를 저장하는 오픈소스 NoSQL DB 입니다.
schema-free ?
collection(= table) 에 저장할 documents(= row, record) 의 구조에 대해 미리 정의 할 필요가 없습니다. 또한 동일한 collection에 다른 구조를 가진 document를 저장할 수 있습니다.
document ?
document 는 key/value 쌍의 데이터를 저장하며 key는 string 이며, values 는 data type 의 어떤 것 도 가능합니다.
feature
Agility & Scalability
스키마의 제약이 없기 때문에 개발시 유연성을 제공합니다.
auto sharding 을 통해 수평 확장이 가능하며
단순 Master/Slave 구조를 넘어 replica set 을 통해 자동으로 장애를 감지하고 복구합니다.
mongoDB 구성 방식
- Stand-Alone – 단독설치… 다 아시죠? ^^
- Replica-Set
Master/slave 구조보다 좀 더 안정적인 방법으로 Master와 같은 역할을 하는 Primary서버에 장애가 감지되면 자동으로 새로운 Primary 서버를 선정하고 동작하게 함으로써 일관성 및 가용성을 보장하는 방식입니다. 1.6 버전 이상에서 사용할 수 있습니다. - Sharding
range 파티션 기법으로 shard key를 중심으로 데이터를 여러 shard 서버에 분산하여 저장하는 방식이며 shard 서버들간의 데이터 balancing 도 모두 자동으로 이루어 집니다.
고가용성을 위해 Replica-set 과 shrding 방식을 함께 사용할 수 있습니다.
이외에도 많은 기능과 장점을 갖고 있지만, 소개는 이정도로 하고
본격적으로 제가 알려드리고 싶은 보안 관련 Tips 을 소개하겠습니다.
mongoDB 를 학습하고자 stand-alone 방식으로 설치를 하고 제일 먼저 든 의문이 ‘root 계정은 어디에서 설정 하는걸까?‘ 였습니다. MySQL 을 설치해 본 분들이라면 저와 같은 의문을 갖게 되실겁니다. 관리자 계정을 추가하는 방법을 찾는 과정에서 몇가지 보안관련 내용을 확인 하게 되었습니다.
mongoDB 보안 관련 Tips
mongoDB 는 설치과정이 매우 간단합니다.
물론 replica-set 이나 sharding 방식에서는 몇가지 설정 과정이 더 필요하지만 기본적으로 stand-alone 방식으로 설치할 경우에는 mysql의 설치 과정 보다 조금 더 간단합니다.
그러나 설치 후에 꼭 확인해야 할 보안 관련 항목이 있습니다.
Tip1. Configuring Authentication
mongoDB 는 설치 후 누구나 DB에 접속 할 수 있습니다.
설치과정 중에 인증과 관련해 설정하는 부분이 없기 때문입니다.
mongoDB 에서도 허가된 사람만 DB에 접속할 수 있도록 계정 및 패스워드를 설정할 수 있습니다.
물론 MySQL과 마찬가지로 DB인스턴스(bin/mongod)를 실행할 때 인증 정보를 사용하겠다는 파라미터(–auth)를 포함해야 합니다.
database 별로 계정과 패스워드를 추가합니다. 아래는 admin 과 test2 라는 데이터베이스에 계정을 추가하는 모습입니다.
[kthserver]$ ./mongodb-linux-x86_64-1.8.1/bin/mongo MongoDB shell version: 1.8.1
connecting to: test
> use admin
switched to db admin
> db.addUser(“admin”, “1234″)
{
“user” : “admin”,
“readOnly” : false,
“pwd” : “08ccdf34dbb3ca05dcc195e30994b628″
}
> use test2
switched to db test2
> db.addUser(“test2user”,”test2pass”)
{
“user” : “test2user”,
“readOnly” : false,
“pwd” : “94cb14434128765982f33b2a5256fc28″
}
> exit
bye
[kthserver]$ ./mongodb-linux-x86_64-1.8.1/bin/mongo test2
MongoDB shell version: 1.8.1
connecting to: test2
> db.user.find()
{ “_id” : ObjectId(“4df97549e53741341c1d8b72″), “name” : “yhee” }
>
계정 설정 후 DB에 접속해보면 여전히 인증절차 없이 user collection (= table) 의 데이터 확인이 가능합니다.
인증을 적용하기 위해서는 –-auth parameter 를 추가하여 DB 인스턴스(bin/mongod)를 재시작해야 합니다
[kthserver]$ ./mongodb-linux-x86_64-1.8.1/bin/mongod –auth
Thu Jun 16 15:54:19 [initandlisten] MongoDB starting : pid=18189 port=27017 dbpath=/data/db/ 64-bit
Thu Jun 16 15:54:19 [initandlisten] db version v1.8.1, pdfile version 4.5
다시 mongo (mysql에서 bin/mysql 과 같은 client 프로그램) 를 통해 DB 접속을 합니다.
test2 DB에서 find (= select ) 를 실행하자 에러가 납니다.
db.auth 구문을 통해 인증을 거치고 나면 비로소 데이터를 확인할 수 있습니다.
[kthserver]$ ./mongodb-linux-x86_64-1.8.1/bin/mongo
MongoDB shell version: 1.8.1
connecting to: test
> use test2
switched to db test2
> db.user.find()
error: {
“$err” : “unauthorized db:test2 lock type:-1 client:127.0.0.1″,
“code” : 10057
}
> db.auth(“test2user”, “test2pass”)
1
> db.user.find()
{ “_id” : ObjectId(“4df97549e53741341c1d8b72″), “name” : “yhee” }
>
DB에 접속후에 db.auth 커맨드로 인증을 하는 과정은 MySQL 을 사용했던 개발자들에겐 다소 어색한 방법이긴 합니다.
MySQL 과 같이 DB접속시 commandline parameter 를 통해 인증 하는 방법도 가능합니다.
[kthserver]$ ./mongodb-linux-x86_64-1.8.1/bin/mongo test2 -utest2user2 -p
MongoDB shell version: 1.8.1
Enter password:
connecting to: test2
> db
test2
> db.user.find()
{ “_id” : ObjectId(“4df97549e53741341c1d8b72″), “name” : “yhee” }
>
각 DataBase별로 계정정보는 system.users 라는 namespace에 저장됩니다. db.removeUser(username) 구문으로 계정 삭제가 가능합니다.
[kthserver]$ ./mongodb-linux-x86_64-1.8.1/bin/mongo test2 -utest2user2 -p
MongoDB shell version: 1.8.1
Enter password:
connecting to: test2
> show collections
system.indexes
system.users
user
> db.system.users.find()
{ “_id” : ObjectId(“4df9a62a56a9d7ada79dd403″), “user” : “test2user”, “readOnly” : false, “pwd” : “94cb14434128765982f33b2a5256fc28″ }
{ “_id” : ObjectId(“4df9a9cd223b76afab6d4e74″), “user” : “test2user2″, “readOnly” : false, “pwd” : “d0c70872c885f082c5b64c0e71367b61″ }
> db.removeUser(“test2user”)
> db.system.users.find()
{ “_id” : ObjectId(“4df9a9cd223b76afab6d4e74″), “user” : “test2user2″, “readOnly” : false, “pwd” : “d0c70872c885f082c5b64c0e71367b61″ }
>
이외에도 패스워드 변경이나 데이터 조작 권한 등을 변경 할 수 있습니다.
Tip2. Stopping Mongo
DB인스턴스(mongod) 를 안전하게(clean exit) 종료하는 방법은 세가지가 있습니다.
첫번째. DB인스턴스를 위와 같이 foreground 로 실행한 경우는 간단히 “Ctrl-C” 를 이용하며 “kill -2 PID,” or “kill -15 PID” 로 도 가능합니다.
두번째. mongo 쉘을 이용하여 admin database 에서 db.shutdownServer() 커맨드를 실행합니다.
[kthserver]$ ./mongodb-linux-x86_64-1.8.1/bin/mongo admin
MongoDB shell version: 1.8.1
connecting to: admin
> show dbs
Thu Jun 16 20:08:45 uncaught exception: listDatabases failed:{
“assertion” : “unauthorized db:admin lock type:-1 client:127.0.0.1″,
“assertionCode” : 10057,
“errmsg” : “db assertion failure”,
“ok” : 0
}
> show collections
Thu Jun 16 20:08:49 uncaught exception: error: {
“$err” : “unauthorized db:admin lock type:-1 client:127.0.0.1″,
“code” : 10057
}
> db.shutdownServer()
Thu Jun 16 20:09:04 DBClientCursor::init call() failed
Thu Jun 16 20:09:04 query failed : admin.$cmd { shutdown: 1.0 } to: 127.0.0.1
server should be down…
Thu Jun 16 20:09:04 trying reconnect to 127.0.1
Thu Jun 16 20:09:04 reconnect 127.0.0.1 failed couldn’t connect to server 127.0.0.1
Thu Jun 16 20:09:04 Error: error doing query: unknown shell/collection.js:150
>
매뉴얼에서는 admin DB에서 인증한 경우에 shutdown 이 가능하다고 했지만 현재 제가 설치한 1.8.1 버전에서는 다른 결과를 보여주고 있었습니다.
mongod (DB인스턴스)는 –auth 파라미터와 함께 구동 된 상태입니다.
admin DB에 접속을 했을 뿐 인증을 하지는 않은 상태에서 db.shutdownServer() 커맨드가 동작했습니다. 물론 mongod 는 shutdown 되었습니다.
마찬가지로 이전 버전인 1.6.5 버전에서 테스트를 진행해보았습니다.
그런데 1.6.5 버전에서는 admin 계정에 대해서 인증이 된 경우에만 db.shutdownServer()가 실행되는 것을 볼 수 있었습니다. 결국 1.8.1 버전에서의 문제로 보입니다.
[kthserver]$ ./mongodb-linux-x86_64-1.6.5/bin/mongo test
MongoDB shell version: 1.6.5
connecting to: test
> show collections
Thu Jun 16 20:45:48 uncaught exception: error: {
“$err” : “unauthorized db:test lock type:-1 client:127.0.0.1″,
“code” : 10057
}
> db.auth(“test_1.6″, “1234″)
1
> db.shutdownServer()
shutdown command only works with the admin database; try ‘use admin’
> use admin
switched to db admin
> db.shutdownServer()
assert failed : unexpected error: “shutdownServer failed: db assertion failure”
Thu Jun 16 20:46:23 uncaught exception: assert failed : unexpected error: “shutdownServer failed: db assertion failure”
> db.auth(“admin_1.6″,”1234″)
1
> db.shutdownServer()
Thu Jun 16 20:46:50 query failed : admin.$cmd { shutdown: 1.0 } to: 127.0.0.1
server should be down…
Thu Jun 16 20:46:50 trying reconnect to 127.0.0.1
Thu Jun 16 20:46:50 reconnect 127.0.0.1 failed couldn’t connect to server 127.0.0.1
Thu Jun 16 20:46:50 MessagingPort say send() errno:9 Bad file descriptor 127.0.0.1:27017
Thu Jun 16 20:46:50 Error: error doing query: unknown (anon):1526
>
마지막으로 driver를 통해서 { “shutdown” : 1 } 커맨드를 이용하여 shutdown 하는 방법입니다.
예를 들면 php 에서는 아래와 같이 테스트 할 수 있습니다.
1.6.5 버전의 mongoDB 를 테스트 한 경우입니다.
<?php
// connect
$m = new Mongo();
// select a database
$db = $m->admin;
// authentication
$db->authenticate(“admin_1.6″,”1234″);
// shutdown
$db->command(array(“shutdown”=>1));
……
로그를 보면 shutdown 이 이루어지고 있는 과정을 확인 할 수 있습니다.
Thu Jun 16 21:29:09 [initandlisten] waiting for connections on port 27017
Thu Jun 16 21:29:09 [websvr] web admin interface listening on port 28017
Thu Jun 16 21:29:18 [initandlisten] connection accepted from 127.0.0.1:47439 #1
Thu Jun 16 21:29:18 [conn1] end connection 127.0.0.1:47439
Thu Jun 16 21:34:33 [initandlisten] connection accepted from 127.0.0.1:47226 #2
Thu Jun 16 21:34:33 [conn2] terminating, shutdown command received
Thu Jun 16 21:34:33 dbexit:
Thu Jun 16 21:34:33 [conn2] shutdown: going to close listening sockets…
Thu Jun 16 21:34:33 [conn2] closing listening socket: 5
Thu Jun 16 21:34:33 [conn2] closing listening socket: 6
Thu Jun 16 21:34:33 [conn2] closing listening socket: 7
Thu Jun 16 21:34:33 [conn2] closing listening socket: 8
Thu Jun 16 21:34:33 [conn2] shutdown: going to flush oplog…
Thu Jun 16 21:34:33 [conn2] shutdown: going to close sockets…
Thu Jun 16 21:34:33 [conn2] shutdown: waiting for fs preallocator…
Thu Jun 16 21:34:33 [conn2] shutdown: closing all files…
Thu Jun 16 21:34:33 closeAllFiles() finished
Thu Jun 16 21:34:33 [conn2] shutdown: removing fs lock…
Thu Jun 16 21:34:33 dbexit: really exiting now
Thu Jun 16 21:34:33 ERROR: Client::~Client _context should be null but is not; client:conn[kthserver]$
마찬가지로 1.8.1 버전을 테스트 한 경우에
mongo shell에서 인증과 상관없이 db.shutdownServer() 가 동작했듯이 driver를 통해서도 인증 없이 shutdown이 진행되었습니다.
1.6.5 버전에서는 인증절차를 통해 shutdown이 동작하지만 1.8.1 버전에서는 shutdown 과 관련한 버그로 보입니다.
이와 관련된 내용입니다. https://jira.mongodb.org/browse/SERVER-3048
현재 사용하는 버전이나 또는 사용 계획이 있는 버전에 대해서 확인 하시기 바랍니다.
Tip3. HTTP interface Security
mongoDB 는 db 상태를 확인할 수 있는 http interface 를 제공합니다.
기본적으로 mongod DB인스턴스가 사용하는 port+1000 번을 사용합니다.
mongd 인스턴스를 defult 27017 port 로 구동했다면 HTTP interface 는 아래와 같이 28017 port 로 확인 합니다.
–auth parameter 없이 mongod 를 구동했다면 누구나 볼 수 있기 때문에 HTTP interface 역시 보안에 문제가 될 수 있습니다.
물론 매뉴얼에서는 보안을 위해 -–auth 옵션으로 mongod 인스턴스를 구동한 경우에는 http interface 접근시 인증을 거쳐야 한다고 설명했지만 실제로 1.8.1 버전에서는 계속해서 인증에러가 발생하는 것을 확인 할 수 있었습니다.
이 또한 mongdb 1.8.1 버전의 버그로 보입니다. 관련된 내용입니다.
https://jira.mongodb.org/browse/SERVER-2917
http://www.mongodb.org/display/DOCS/Http+Interface#HttpInterface-HTTPConsoleSecurity
현재 사용하는 버전이나 또는 사용 계획이 있는 버전에 대해서 확인 하시기 바랍니다.
저는 Http interface 를 사용하지 않도록 설정했습니다.
mongod 인스턴스 시작시 –-nohttpinterface 파라미터를 추가하면 됩니다.
[kthserver]$ ./mongodb-linux-x86_64-1.8.1/bin/mongod –auth –nohttpinterface
이상 세가지 보안 관련 항목에 대해서 살펴봤습니다.
요약하면,
1. mongoDB 설치 후 admin 계정과 각 DATABASE 별로 접근을 허용할 계정을 설정하시기 바랍니다. –-auth parameter 와 함께 mongod 인스턴스를 구동하시기 바랍니다.
2. DB 를 shutdown 하는 것은 관리자만이 할 수 있어야 합니다. –-auth parameter 와 함께 mongod 인스턴스를 구동하시기 바랍니다. 또한 정상적으로 인증이 이루어지는 현재 사용 중이거나 사용계획이 있는 버전에 대하여 확인 하시기 바랍니다.
3. 누구나 Http interface 에 접근해서는 안됩니다. –-auth parameter 와 함께 mongod 인스턴스를 구동하시기 바랍니다. 물론, mongod 인스턴스 구동시 disable 할 수 있습니다.
편집자 주 : 저희 개발자블로그에 올라왔던 “공간 데이터베이스(Spatial DB) 란 무엇인가?” 글에도 많은분들이 mongoDB에 관심가지고 계시다는 댓글을 달아주셨는데요. mongoDB 가 공간 데이터베이스에서 어떻게 사용되는지 보시려면 참고하시기 바랍니다.
출처 - http://dev.kthcorp.com/2011/06/22/mongodb-security-tips-for-beginners/
'DB > MongoDB' 카테고리의 다른 글
mongodb - how to use (0) | 2013.05.21 |
---|---|
mongodb - mongod.conf(web interface enable) (0) | 2013.05.19 |
mongodb - Hadoop과 연동한 구축사례 (0) | 2013.04.29 |
mongodb - 고려 사항 (0) | 2013.04.29 |
MongoDB 소개 (0) | 2013.01.07 |