.. _integrated-googleform-iprequest: ì‚¬ìš©ìž IP ì‹ ì² ì—°ë™(With Google Form) ============================================ 본 ê°€ì´ë“œëŠ” Google Form(app script)ì„ í™œìš©í•˜ì—¬ Genian NACì— ì„œë¹„ìŠ¤ì¤‘ í•˜ë‚˜ì¸ IPì‹ ì²ì‹œìŠ¤í…œì„ 사용하는 ë°©ë²•ì„ ì•ˆë‚´í•©ë‹ˆë‹¤. 개요 --------------- Google Formì˜ Apps script와 Genian NACì˜ RestFul API를 활용하여 Genian NAC를 사용하는 사용ìžê°€ ë„¤íŠ¸ì›Œí¬ ìžì›ì„ 사용하기 ì „ 보다 편리하게 IP와 MACì„ ì‹ ì²/ìŠ¹ì¸ ë°›ê³ ë¹„ì¸ê°€/ì¸ê°€ 사용ìžì— 대한 ê°ì‚¬ ì¦ì ì„ ë‚¨ê¸¸ 수 있습니다. 권장 ë²„ì „ ^^^^^^^^^^^^ .. csv-table:: :header: "ì œí’ˆëª… (구성요소)", "ë²„ì „", "ë¹„ê³ " :widths: 30 30 40 "Genian NAC (ì •ì±…ì„œë²„)", "V5.0.55 ì´ìƒ", "" ì—°ë™ì˜ 목ì ------------------- Goole Formê³¼ Genian NAC IP ì‹ ì² ì—°ë™ì€ 다ìŒì˜ 효과를 ì œê³µí•©ë‹ˆë‹¤. **ì‚¬ìš©ìž ì¹œí™”ì IP ì‹ ì² í”„ë¡œì„¸ìŠ¤** - ì¼ì •í•œ í‹€ì´ ë§Œë“¤ì–´ì ¸ìžˆëŠ” 기본 ì œê³µ IP ì‹ ì²í™”ë©´ì´ ì•„ë‹Œ 사용ìžì¸¡ì—ì„œ 개발한 UI를 사용하여 IPì‹ ì² ì‹œìŠ¤í…œì„ êµ¬ì¶•í• ìˆ˜ 있습니다. **ê´€ë¦¬ìž ì¹œí™”ì IP ì‹ ì² í”„ë¡œì„¸ìŠ¤** - 관리ìžê°€ ì›í•˜ëŠ” IP ì‹ ì²/ìŠ¹ì¸ í”„ë¡œì„¸ìŠ¤ë¥¼ 만들 수 있으며 ì–¸ì œë“ ì§€ 프로세스를 변경 í• ìˆ˜ 있습니다. IPì‹ ì² ì—°ë™ ì‹œë‚˜ë¦¬ì˜¤ ------------------------------- 1. 사용ìžê°€ Google Form 으로 ì‹ ì² ë‚´ìš© 작성 2. Google Sheets ì— ì‹ ì² ë‚´ìš© ë“±ë¡ 3. ì‹ ì²í•œ ë‚´ìš©ì„ ë°”íƒ•ìœ¼ë¡œ Genian NACì— IP ì‹ ì² 4. 관리ìžê°€ Google Sheetsì—ì„œ 승ì¸ìœ¼ë¡œ ê°’ 변경 5. 관리ìžê°€ 승ì¸í•œ IP ì‹ ì²ì„œ ìŠ¹ì¸ .. image:: /images/googleformiprequest1.png :width: 600px ì‚¬ì „ 준비 ì‚¬í• -------------------- - 외부와 í†µì‹ ì´ ê°€ëŠ¥í•œ Genian NAC ì •ì±… 서버 - 관리ìžì˜ API 키 - ì •ì±…ì„œë²„ì— ë“±ë¡ëœ 센서 장비 ë° ì„¼ì„œì˜ ë…¸ë“œ ì•„ì´ë”” - Google Form 1. Genian NAC | Google Apps Scriptì—ì„œ NACì˜ API를 호출하기 위해서는 ë„¤íŠ¸ì›Œí¬ ì ‘ê·¼ì´ ê°€ëŠ¥í•´ì•¼í•˜ê¸° ë•Œë¬¸ì— | í´ë¼ìš°ë“œ ê¸°ë°˜ì˜ NAC 환경ì´ê±°ë‚˜ NACì— ì ‘ê·¼í• ìˆ˜ 있ë„ë¡ ë„ë©”ì¸ ì„¤ì •ì„ ë¨¼ì € 해야합니다. 여기서는 ì ‘ê·¼ 편ì˜ì„±ì„ 위해 Testìš© Cloud NAC를 ìƒì„±í•˜ì—¬ 진행합니다. - Cloud NAC 사ì´íŠ¸ ìƒì„± - genians(https://my.genians.co.kr/) 사ì´íŠ¸ì—ì„œ ê³„ì • ìƒì„± ë° ì‚¬ì´íŠ¸ ìƒì„± - 센서 ì„¤ì • ë° API Key 발급 - IP ì‹ ì²ì„ 하기 위해서는 ê´€ë¦¬í•˜ê³ ìžˆëŠ” 네트워í¬ì— NAC 센서를 연결하여 ìƒì„±í•œ 사ì´íŠ¸ì— 등ë¡í•´ì•¼í•©ë‹ˆë‹¤. NAC 센서 ìƒì„± ë° ì„¤ì •ì€ :ref:`installing-network-sensor` 를 ì°¸ê³ í•˜ì„¸ìš”. - API ì—°ë™ì„ 위해서는 관리ìžì˜ API Key를 ìƒì„±í•´ì•¼í•©ë‹ˆë‹¤. - 관리 > ì‚¬ìš©ìž > 관리ìžì˜ ìƒì„¸í™”ë©´ì—ì„œ API Key를 ìƒì„±í•©ë‹ˆë‹¤. - 센서 Node ID í™•ì¸ - IP ì‹ ì²ì„ í• ë•Œ ì‚¬ìš©í•˜ê³ ìží•˜ëŠ” IP대ì—ì„ ì„ íƒí•˜ê²Œ ë˜ëŠ”ë° ì´ë•Œ 센서를 ì„ íƒí•˜ê²Œë©ë‹ˆë‹¤. ì„ íƒí•˜ëŠ” ìž¥ë¹„ì˜ Keyê°€ Sensor Node ID입니다. - 시스템 > ì„¼ì„œì„¤ì • > 센서 ìƒì„¸í™”ë©´ì˜ Node ID를 확ì¸í•©ë‹ˆë‹¤. 2. Google Form - 사용ìžì—게 IP ì‹ ì²ì„ ë°›ì„ ìˆ˜ 있는 Google 설문지 í¼ì„ ì„¤ì •í•©ë‹ˆë‹¤. - Google Drive 메뉴ì—ì„œ Google 설문지 메뉴를 ì„ íƒí•©ë‹ˆë‹¤. - IP ì‹ ì²ì„œ 작성 ì‹œ 필수 ìž…ë ¥ì´ í•„ìš”í•œ í•ëª©ì„ ì„¤ì •í•©ë‹ˆë‹¤.(※ ê° ì‚¬ì´íŠ¸ë§ˆë‹¤ 요구사í•ì€ 다를 수 있으며 í™˜ê²½ì— ë§žê²Œ 구성합니다) - 본 문서ì—서는 기본ì ì¸ í•ëª©ì„ 기반하여 ì„¤ì •í–ˆìœ¼ë©° ì„¤ì •ë‚´ìš©ì€ ì•„ëž˜ì™€ 같습니다. .. code-block:: bash 사용위치: ë“œë¡ë‹¤ìš´ - ì‚¬ìš©í•˜ê³ ìžˆëŠ” 센서를 추가합니다. 여러 í•ëª©ì¤‘ì— ì„ íƒí• 수 있ë„ë¡ ë“œë¡ë‹¤ìš´ì„ 사용하며 êµ¬ë¶„ì„ ìœ„í•´ IP 주소를 ë¼ë²¨ë¡œ ì§€ì •í–ˆìŠµë‹ˆë‹¤. ì‚¬ìš©ìž ID: 단답형 í…스트 - 사용ìžì˜ ID를 ìž…ë ¥í•©ë‹ˆë‹¤. ì‚¬ìš©ìž ëª…: 단답형 í…스트 ì‹ ì²ìž ID: 단답형 í…스트 ì‹ ì²ìž 명: 단답형 í…스트 ìš©ë„: ë“œë¡ë‹¤ìš´ - ìœ ë™, ê³ ì • IP 사용ì¸ì§€ ìš©ë„를 ì„ íƒí• 수 있습니다. IP 주소: 단답형 í…스트 - ê³ ì • IP ìš©ë„ì¸ ê²½ìš° IP를 ìž…ë ¥í•©ë‹ˆë‹¤. MAC 주소: 단답형 í…스트 - ê³ ì • IP ìš©ë„ì¸ ê²½ìš° MAC 주소를 ìž…ë ¥ 받습니다. ì´ë©”ì¼: 단답형 í…스트 - ì‹ ì² ê²°ê³¼ë¥¼ ë°›ì„ ì´ë©”ì¼ ì£¼ì†Œë¥¼ ìž…ë ¥ë°›ìŠµë‹ˆë‹¤. .. image:: /images/googleformiprequest2.png :width: 600px .. note:: ì§ˆë¬¸ì— ì‚¬ìš©ë˜ëŠ” í•ëª©ëª…ì€ Apps script ì—ì„œ 그대로 사용ë˜ëŠ” ê°’ì´ë¯€ë¡œ ì •í™•ížˆ 작성합니다. - Sheetsì˜ ì‘답íƒìœ¼ë¡œ ì´ë™í•˜ì—¬ ê²°ê³¼ì— ëŒ€í•œ Sheets를 ìƒì„±í•©ë‹ˆë‹¤. - ì‘답 > Sheetsì—ì„œ 보기 í´ë¦ - Sheets 가장 마지막 ì—´ì—ì„œ 컬럼 ë‘개를 추가 합니다. - 승ì¸ì—¬ë¶€: 관리ìžê°€ ìŠ¹ì¸ ì—¬ë¶€ë¥¼ ì„ íƒí• 수 있ë„ë¡ ì»¬ëŸ¼ì„ ì¶”ê°€í•©ë‹ˆë‹¤.(ë“œë¡ë‹¤ìš´) - idx: IP ì‹ ì² ì´í›„ ì •ì±…ì„œë²„ì— ë“±ë¡ë˜ëŠ” ì‹ ì²ì„œì˜ index ê°’ì„ ì—…ë°ì´íŠ¸ í• ì»¬ëŸ¼ìž…ë‹ˆë‹¤. 3. Apps Script - ì„¤ë¬¸ì´ ìž‘ì„±ë˜ì–´ ì‹œíŠ¸ì— ë‚´ìš©ì´ ì €ìž¥ë 때마다 실행ë 스í¬ë¦½íŠ¸ë¥¼ 작성합니다. - ì‹¤í–‰í• ìŠ¤í¬ë¦½íŠ¸ 종류는 ë‘종류 입니다. - ì‹ ì²ì„œ 작성 ì‹œ ì‹ ì²ì„œ ë“±ë¡ ìŠ¤í¬ë¦½íŠ¸ - ê´€ë¦¬ìž ìŠ¹ì¸ ì‹œ ì‹ ì²ì„œ ìŠ¹ì¸ ìŠ¤í¬ë¦½íŠ¸ - Sheets 메뉴 > 확장 프로그램 > Apps Script를 ì„ íƒí•©ë‹ˆë‹¤. - 스í¬ë¦½íŠ¸ë¥¼ 작성하기 ì „ NAC Swagger 페ì´ì§€ì—ì„œ ì‚¬ìš©í• API를 확ì¸í•©ë‹ˆë‹¤. - swagger는 Genian NACì—ì„œ 사용가능한 API를 문서화한 ë„구ì´ë©° {https://Domain/mc2/swagger/index.html} ì—ì„œ í™•ì¸ ê°€ëŠ¥í•©ë‹ˆë‹¤. - ìƒì„±ê³¼ 승ì¸ì„ 하기 위해 POST **/mc2/rest/applications/ips** (ì‹ ì²ì„œ ìƒì„±) 와 PUT **/mc2/rest/applications/ips/ì‹ ì²ì„œidx** (ì‹ ì²ì„œ ìƒíƒœ ìˆ˜ì •) API를 확ì¸í•©ë‹ˆë‹¤. .. image:: /images/googleformiprequest3.png :width: 600px - Google formì´ ìž‘ì„±ë 때마다 실행ë 스í¬ë¦½íŠ¸ë¥¼ 작성합니다. - IP ì‹ ì²ì„œ ë“±ë¡ .. code-block:: bash function onFormSubmit(e) { const itemResponses = e.namedValues; // 관리ìžì˜ API Key를 ìƒì„±í•œ ë’¤ api 호출 ì‹œ ì‚¬ìš©í• ìˆ˜ 있ë„ë¡ ì„ ì–¸í•œë‹¤. const API_KEY = "관리ìžì˜ API KEY ê°’" // REST API 를 í˜¸ì¶œí• url const url = "https://[ë„ë©”ì¸]/mc2/rest/applications/ips"; const applyResJson = applyIpApplication(url, API_KEY, itemResponses); if(applyResJson !== null) { const idx = applyResJson.ipApps[0].idx; const sheet = e.range.getSheet(); const row = e.range.getRowIndex(); sheet.getRange(row, 12).setValue(idx); } } /** * IP ì‹ ì²ì„œ ì‹ ì² í›„ ì‘ë‹µê°’ì„ json ê°ì²´ë¡œ 반환 */ function applyIpApplication(_url, apiKey, itemResponses) { const url = _url + "?apiKey=" + apiKey; const payload = getApplicationPayload(itemResponses); // REST API 호출 const options = { "method": "POST", "contentType": "application/json;charset=UTF-8", "headers": { "accept": "application/json;charset=UTF-8" }, "payload": payload }; const response = UrlFetchApp.fetch(url, options); let resJson = null; try { resJson = JSON.parse(response.getContentText()); } catch(e) { resJson = null; } return resJson; } /** * IP ì‹ ì²ì„œ ì‹ ì² ì‹œ ìž…ë ¥ëœ ê°’ì„ json string 으로 변환 */ function getApplicationPayload(itemResponses) { // ì„¼ì„œì˜ nidì„ ê°€ì ¸ì˜¬ 수 있ë„ë¡ ê°ì²´ë¡œ 미리 ì„ ì–¸ const sensorDatas = {'172.29.132.0/24': '[센서 Node ID]' }; // ìš©ë„ì˜ value ê°’ ì„ ì–¸ const purposeDatas = {'ìœ ë™IP사용': 'USERIP_VARIABLE', 'ê³ ì •IP사용': 'USERIP_STATIC'}; // ì‘답 ë°ì´í„° 가공 const purposeType = itemResponses["ìš©ë„"][0]; const data = {}; // ì‹ ê·œì‹ ì² : 1 data["appType"] = 1; data["sensorNid"] = sensorDatas[itemResponses["사용위치"][0]]; data["id"] = itemResponses["ì‚¬ìš©ìž ID"][0]; data["name"] = itemResponses["ì‚¬ìš©ìž ëª…"][0]; data["applicantId"] = itemResponses["ì‹ ì²ìž ID"][0]; data["applicantName"] = itemResponses["ì‹ ì²ìž 명"][0]; data["purposeCode"] = purposeDatas[itemResponses["ìš©ë„"][0]]; if(purposeType === 'ê³ ì •IP사용') { data["ipStr"] = itemResponses["IP 주소"][0]; data["mac"] = itemResponses["MAC 주소"][0]; } data["alarmEmail"] = itemResponses["ì´ë©”ì¼"][0]; const payload = JSON.stringify([ data ]); return payload; } - function 설명 - onFormSubmit() - Google formì´ ìž‘ì„±ëœ í›„ 실행ë˜ëŠ” 진입ì ì´ ë˜ëŠ” function - applyIpApplication() - ì‹ ì²ì„œ API를 호출하는 function. ìž‘ì—…ì´ ì™„ë£Œë˜ë©´ ê²°ê³¼ê°’ì„ json 형태로 리턴합니다. - getApplicationPayload() - ì‹ ì²ì„œ API 호출 ì‹œ formì— ìž…ë ¥ëœ ì •ë³´ë¥¼ 바탕으로 파ë¼ë¯¸í„°ë¥¼ ìƒì„±í•©ë‹ˆë‹¤. - ì‚¬ì „ ì •ì˜í•œ ì •ë³´ .. code-block:: bash const sensorDatas = {'172.29.50.xx': '센서 Node ID'}; // ìš©ë„ì˜ value ê°’ ì„ ì–¸ const purposeDatas = {'ìœ ë™IP사용': 'USERIP_VARIABLE', 'ê³ ì •IP사용': 'USERIP_STATIC'}; - IP ì‹ ì²ì„ í• ë•Œ ì„¼ì„œì˜ Node ID ê°’ì„ íŒŒë¼ë¯¸í„°ë¡œ ì „ì†¡í•´ì•¼í•˜ëŠ”ë° formì— Node ID를 ë…¸ì¶œí•˜ëŠ”ê²ƒì€ ì‚¬ìš©ìžê°€ ì¸ì‹í•˜ê¸° ì–´ë ¤ìš´ ì •ë³´ì´ê¸° ë•Œë¬¸ì— í•´ë‹¹ ë¶€ë¶„ì´ ì¹˜í™˜ì´ ë 수 있ë„ë¡ ì‚¬ì „ì— ì •ì˜í•´ë†“습니다. - IP ì‹ ì² ìŠ¹ì¸ .. code-block:: bash /** * 시트ì—ì„œ ìŠ¹ì¸ ì»¬ëŸ¼ ê°’ì´ ë³€ê²½ë˜ë©´ 호출 * @param {e} ì´ë²¤íŠ¸ ê°ì²´ */ function onEdit(e) { const sheet = e.source.getActiveSheet(); const targetColumn = 11; // idx 컬럼, 0 시작 ë°°ì—´ì—ì„œ ê°€ì ¸ì˜¤ëŠ” ê°’ì´ê¸° ë•Œë¬¸ì— ì»¬ëŸ¼ ì¸ë±ìŠ¤ ê°’ -1 const editedRow = e.range.getRow(); const val = e.range.getValue(); // ìˆ˜ì •ëœ ì…€ì˜ ROWì— idxê°’ì´ ìžˆëŠ” 경우ì—만 처리 if (val === '승ì¸') { const record = sheet.getRange(editedRow, 1, 1, sheet.getLastColumn()).getValues()[0]; const idx = record[targetColumn]; if(idx !== '') { approveIpApplication(idx); Logger.log("Value of val: " + idx); } } } /** * IP ì‹ ì²ì„œ ìŠ¹ì¸ */ function approveIpApplication(idx) { // 관리ìžì˜ API Key를 ìƒì„±í•œ ë’¤ api 호출 ì‹œ ì‚¬ìš©í• ìˆ˜ 있ë„ë¡ ì„ ì–¸í•œë‹¤. const API_KEY = "[ê´€ë¦¬ìž API KEYê°’]" const apiUrl = "[ë„ë©”ì¸]/mc2/rest/applications/ips/" + idx + "?apiKey=" + API_KEY; const options = { "method": "PUT", "contentType": "application/x-www-form-urlencoded", "headers": { "accept": "application/json;charset=UTF-8" }, "payload": "cmd=approve" }; try { const response = UrlFetchApp.fetch(apiUrl, options); } catch (err) { Logger.log("Error: " + err); } } - function 설명 - onEdit() - ì‹œíŠ¸ì˜ ì»¬ëŸ¼ê°’ì„ ê´€ë¦¬ìžê°€ ìˆ˜ì •í–ˆì„ë•Œ 호출ë˜ëŠ” function - 관리ìžê°€ ìˆ˜ì •í•œ ì»¬ëŸ¼ì´ ìŠ¹ì¸ì—¬ë¶€ 컬럼ì´ë©´ì„œ 승ì¸ìœ¼ë¡œ ê°’ì„ ë³€ê²½í• ê²½ìš° approveIpApplication() functionì„ í˜¸ì¶œí•œë‹¤. - approveIpApplication() - ì„ íƒí•œ ë ˆì½”ë“œì˜ IP ì‹ ì²ì„œë¥¼ 승ì¸í•œë‹¤. - 트리거로 ë“±ë¡ - 트리거 메뉴로 ì´ë™í•©ë‹ˆë‹¤. - 트리거 추가 - IP ì‹ ì²ì„œ ë“±ë¡ íŠ¸ë¦¬ê±° - ì‹¤í–‰í• í•¨ìˆ˜ ì„ íƒ: 스í¬ë¦½íŠ¸ì— 작성한 onFormSubmit() ì„ íƒ - ì‹¤í–‰í• ë°°í¬: Head - ì´ë²¤íŠ¸ 소스 ì„ íƒ: ìŠ¤í”„ë ˆë“œì‹œíŠ¸ì—ì„œ - ì´ë²¤íŠ¸ ìœ í˜• ì„ íƒ: ì–‘ì‹ ì œì¶œ ì‹œ .. image:: /images/googleformiprequest4.png :width: 400px - IP ì‹ ì²ì„œ ìŠ¹ì¸ íŠ¸ë¦¬ê±° - ì‹¤í–‰í• í•¨ìˆ˜ ì„ íƒ: 스í¬ë¦½íŠ¸ì— 작성한 onFormSubmit() ì„ íƒ - ì‹¤í–‰í• ë°°í¬: Head - ì´ë²¤íŠ¸ 소스 ì„ íƒ: ìŠ¤í”„ë ˆë“œì‹œíŠ¸ì—ì„œ - ì´ë²¤íŠ¸ ìœ í˜• ì„ íƒ: ìˆ˜ì • ì‹œ .. image:: /images/googleformiprequest5.png :width: 400px - 설문 작성 ë° ì‹¤í–‰ í™•ì¸ - 실행 í™•ì¸ - ì„¤ë¬¸ì„ ìž‘ì„± 후 í™•ì¸ - 시트ì—ì„œ ìŠ¹ì¸ í›„ í™•ì¸ - Logger.log ë¡œ 확ì¸í• ë‚´ìš©ì„ ìž‘ì„±í•´ 놓으면 실행단계ì—ì„œ 확ì¸ì´ 가능합니다. - NACì—ì„œ IP ì‹ ì² ê²°ê³¼ í™•ì¸ - 관리 > ì‹ ì² > IP 사용 ì‹ ì²ì„œ > 결과조회 메뉴 ì´ë™ - 승ì¸ëœ ì‹ ì²ì„œ í™•ì¸ .. image:: /images/googleformiprequest6.png :width: 600px