지난번에 테스트 해서 공유드린 내용의 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 인증서와 키를 직접 생성 가능합니다.)
HTTPS 핸들러 작성이 완료되었으면 실제 서비스를 수행(DB 수행) 하기 위해서 MPGW 정책을 작성합니다.
IBM DataPower Gateway 의 정책 디자이너에서 하단과 같이 정책을 생성합니다.
① 들어오는 모든 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 으로 설정하고 해당 설정을 저장 합니다.
해당 설정이 정상적으로 완료되면 하단과 같이 지금 만든 MPGW 서비스가 on 되어서 작동 상태로 변경된 것을 확인 가능합니다.
#4) WAS 에서 테스트 수행하는 것을 가정하여 간단하게 테스트를 진행
JSON 형태로 SQL 을 HTTPS 로 요청하게 되면 SSL 을 통해서 하단과 같이 IBM DataPower Gateway 가 실제 DB 호출을 수행한 후 결과값을 JSON 형태로 보내주는 것을 확인 가능합니다.
추가 #1 : 이전 방식보다 MPGW 를 사용하는 방식이 보안적으로 더 높은 구성이 가능하다는 이유는 Secure Gateway 로서의 IBM DataPower Gateway 의 기능을 모두다 활용할 수 있기 때문입니다. 예를 들어 MPGE 정책의 맨 앞단에 하단과 같은 gatewayscript 를 추가하여 사전에 지정된 IP 만 해당 요청을 수행하게 할 수 있습니다.
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 정책 예시
댓글