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 역시 보안에 문제가 될 수 있습니다.

 

http://localhost:28017 or http://1.2.3.4:28017

물론 매뉴얼에서는 보안을 위해 -–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 가 공간 데이터베이스에서 어떻게 사용되는지 보시려면 참고하시기 바랍니다.


About the author

Fiona2003년 Oracle 을 시작으로 DBMS에 관심을 갖게 되었고, KTH에서 Community , SNS 서비스를 중심으로 웹개발, DB설계 및 튜닝 등의 다양한 경험을 쌓고 있습니다.



출처 - 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
Posted by linuxism
,