지난번에 테스트 해서 공유드린 내용의 2부 겪으로 Cloud 상에 있는 WAS 와 Legacy 에 있는 DB 연결을 좀 더 안정적으로 수행하기 위해서 IBM DataPower Gateway 가 할 수 있는 추가 방안을 모색해서 테스트 해보고 그 내용을 공유드립니다.
요구사항 : Cloud 에 WAS 를 구성하고 기존 Legacy 에 DB 를 둘 예정인데 이를 보안적으로 보완하기 위한 구성
구성 : WAS on Cloud --> IBM DataPower Gateway on Legacy -> DB on Legacy
- WAS 에서 REST/JSON 형태로 SQL 구문을 IBM DataPower Gateway 로 전달하면 DataPower 가 SQL 구문을 직접 DB 에 던져 수행후 그 결과를 JSON 으로 반환
차이 : WAS 에서 Application 변경이 필요하지만 DB 호출 및 응답을 IBM DataPower Gateway 가 대신 수행하므로 Legacy 에 있는 DB 가 직접 Cloud 로 노출되지 않음
IBM DataPower Gateway 에서 요청을 위임 받으므로 해당 솔루션이 Secure Gateway 로서 가지고 있는 다양한 보안/정책등을 통해 보다 강화된 보안/제어 가능
#1) WAS 에서 REST/JSON 형태로 request 를 보낼때 그 안에 SQL 구문을 하단과 같은 형태로 보낸다고 가정
{ "SQL" : "select * from IF_MRO_S where SITE_CD='00001'" }
#2) IBM DataPower Gateway 에서 DB 직접 호출을 위한 SQL 데이터 소스 작성
IBM DataPower Gateway 는 DB 접속을 위한 다양한 SQL 데이터 소스를 작성 가능하며 하단과 같이 DB 접속 정보를 넣어 줍니다.
(IBM DataPower Gateway 는 Oracle, IBM DB2, MS SQL, Sybase 등 다양한 DB 를 ODBC 형태로 지원 가능하며 테스트는 간단하게 Oracle 로 수행했습니다.)


#3) IBM DataPower Gateway 에서 HTTPS 요청을 받고 DB 를 호출할 Multi-Protocol Gateway(MPGW) 작성
요청을 받았을때 DB 작업 수행을 할 새로운 MPGW 를 하나 작성합니다. MPGW 는 하단과 같이 HTTP, HTTPS, JMS, FTP 등 다양한 프로토콜을 받아서 처리 및 다양한 프로토콜로 변환 가능한 서비스 중의 하나입니다.

MPGW 가 보유한 다양한 프로토콜 핸들러 중에서 HTTPS 핸들러를 선택합니다.

특정 포트로 서비스 할 수 있는 HTTPS 핸들러 설정을 작성합니다. (SSL 인증서가 필요하며 IBM DataPower 에서는 Crpyto Tool(암호 도구) 을 이용해서 사용자 SSL 인증서와 키를 직접 생성 가능합니다.)

.png)
HTTPS 핸들러 작성이 완료되었으면 실제 서비스를 수행(DB 수행) 하기 위해서 MPGW 정책을 작성합니다.

.png)
IBM DataPower Gateway 의 정책 디자이너에서 하단과 같이 정책을 생성합니다.

.png)
① 들어오는 모든 URL 대상으로 MPGW 정책 수행
Match
URL : *
② IBM DataPower Gateway 에서 직접 DB 작업을 수행후에 바로 응답을 보낼거라 응답 규칙을 만들지 않을것이라는 설정
Set Variable
service/mpgw/skip-backside = 1
③ Header 값의 contecnt-type 변경
Set Variable
service/set-request-header/content-type = application/json
④ 입력받은 JSON 을 내부에서 처리하기 위한 xml 형태의 JSONx 로 변환
Convert Query Params to XML
json
⑤ 입력받은 JSON 의 SQL 부분의 값을 가져와 미리 만들어둔 SQL 데이터 소스를 통해서 SQL query 수행
(XSLT 로 샘플을 작성했으며 Javascript 기반인 Gatewayscript 를 사용해서 작성도 가능합니다.)
sqlSelect01.xslt
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dp="http://www.datapower.com/extensions"
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx"
xmlns="http://www.w3.org/2005/Atom"
exclude-result-prefixes="dp" >
<xsl:template match="json:string[@name]">
<xsl:variable name="query">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:variable name="result" select="dp:sql-execute('OracleDS01',$query)" />
<xsl:copy-of select="$result" />
</xsl:template>
</xsl:stylesheet>
⑥ SQL querty 수행 결과를 XML 에서 JSON 으로 포멧 변환
xmltojson.xslt
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:func="http://exslt.org/functions"
xmlns:xalan="http://xml.apache.org/xslt"
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx"
xmlns:regexp="http://exslt.org/regular-expressions"
xmlns:dp="http://www.datapower.com/extensions"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:dpquery="http://www.datapower.com/param/query"
extension-element-prefixes="dp"
exclude-result-prefixes="dp" >
<xsl:template match="/*[node()]">
<xsl:text>{</xsl:text>
<xsl:apply-templates select="." mode="detect" />
<xsl:text>}</xsl:text>
</xsl:template>
<xsl:template match="*" mode="detect">
<xsl:choose>
<xsl:when test="name(preceding-sibling::*[1]) = name(current()) and name(following-sibling::*[1]) != name(current())">
<xsl:apply-templates select="." mode="obj-content" />
<xsl:text>]</xsl:text>
<xsl:if test="count(following-sibling::*[name() != name(current())]) > 0">, </xsl:if>
</xsl:when>
<xsl:when test="name(preceding-sibling::*[1]) = name(current())">
<xsl:apply-templates select="." mode="obj-content" />
<xsl:if test="name(following-sibling::*) = name(current())">, </xsl:if>
</xsl:when>
<xsl:when test="following-sibling::*[1][name() = name(current())]">
<xsl:text>"</xsl:text><xsl:value-of select="name()"/><xsl:text>" : [</xsl:text>
<xsl:apply-templates select="." mode="obj-content" /><xsl:text>, </xsl:text>
</xsl:when>
<xsl:when test="count(./child::*) > 0 or count(@*) > 0">
<xsl:text>"</xsl:text><xsl:value-of select="name()"/>" : <xsl:apply-templates select="." mode="obj-content" />
<xsl:if test="count(following-sibling::*) > 0">, </xsl:if>
</xsl:when>
<xsl:when test="count(./child::*) = 0">
<xsl:text>"</xsl:text><xsl:value-of select="name()"/>" : "<xsl:apply-templates select="."/><xsl:text>"</xsl:text>
<xsl:if test="count(following-sibling::*) > 0">, </xsl:if>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="*" mode="obj-content">
<xsl:text>{</xsl:text>
<xsl:apply-templates select="@*" mode="attr" />
<xsl:if test="count(@*) > 0 and (count(child::*) > 0 or text())">, </xsl:if>
<xsl:apply-templates select="./*" mode="detect" />
<xsl:if test="count(child::*) = 0 and text() and not(@*)">
<xsl:text>"</xsl:text><xsl:value-of select="name()"/>" : "<xsl:value-of select="text()"/><xsl:text>"</xsl:text>
</xsl:if>
<xsl:if test="count(child::*) = 0 and text() and @*">
<xsl:text>"text" : "</xsl:text><xsl:value-of select="text()"/><xsl:text>"</xsl:text>
</xsl:if>
<xsl:text>}</xsl:text>
<xsl:if test="position() < last()">, </xsl:if>
</xsl:template>
<xsl:template match="@*" mode="attr">
<xsl:text>"</xsl:text><xsl:value-of select="name()"/>" : "<xsl:value-of select="."/><xsl:text>"</xsl:text>
<xsl:if test="position() < last()">,</xsl:if>
</xsl:template>
<xsl:template match="node/@TEXT | text()" name="removeBreaks">
<xsl:param name="pText" select="normalize-space(.)"/>
<xsl:choose>
<xsl:when test="not(contains($pText, '
'))"><xsl:copy-of select="$pText"/></xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(substring-before($pText, '
'), ' ')"/>
<xsl:call-template name="removeBreaks">
<xsl:with-param name="pText" select="substring-after($pText, '
')"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
위와 같이 하면 MPGW 정책 작성을 하실 수 있습니다. 이후 MPGW 의 응답 유형 타입과 요청 유형 타입을 둘다 JSON 으로 설정하고 해당 설정을 저장 합니다.

.png)
해당 설정이 정상적으로 완료되면 하단과 같이 지금 만든 MPGW 서비스가 on 되어서 작동 상태로 변경된 것을 확인 가능합니다.

.png)
#4) WAS 에서 테스트 수행하는 것을 가정하여 간단하게 테스트를 진행
JSON 형태로 SQL 을 HTTPS 로 요청하게 되면 SSL 을 통해서 하단과 같이 IBM DataPower Gateway 가 실제 DB 호출을 수행한 후 결과값을 JSON 형태로 보내주는 것을 확인 가능합니다.

.png)
추가 #1 : 이전 방식보다 MPGW 를 사용하는 방식이 보안적으로 더 높은 구성이 가능하다는 이유는 Secure Gateway 로서의 IBM DataPower Gateway 의 기능을 모두다 활용할 수 있기 때문입니다. 예를 들어 MPGE 정책의 맨 앞단에 하단과 같은 gatewayscript 를 추가하여 사전에 지정된 IP 만 해당 요청을 수행하게 할 수 있습니다.

.png)
validIP.js
var sm = require ('service-metadata');
//var hm = require('header-metadata');
//var clientIP = hm.current.get('X-Client-IP');
var clientIP = sm.getVar('var://service/transaction-client');
var allowIP = session.parameters.allowIP;
if (clientIP != allowIP) {
session.reject(clientIP + " is not allowed.");
}else {
}
MPGW 정책 예시

댓글