2020년 11월 25일 수요일

RedHat7&Centos7 APM(apache/Php/mysql) 설치

[ 버전정보 ]

  • Httpd 2.4
  • Php 7.3
  • mariaDB 5.5


[ EC2에 APM설치 ]

  • httpd2.4 설치

#sudo yum install httpd

#httpd -v
Server version: Apache/2.4.6 (Red Hat Enterprise Linux)

 

  • Apache httpd vhost 설정

#sudo vi /etc/httpd/conf/httpd.conf

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 Listen 8080 (추가) ..... (VirtualHost 추가) <VirtualHost *:80> ServerName servername:80 ServerAdmin root@example.com DocumentRoot "/var/www/html/server1" CustomLog "logs/access_log" combined ErrorLog "logs/error_log" <Directory "/var/www/html/server1"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> </VirtualHost> <VirtualHost *:8080> ServerName servername:8080 ServerAdmin root@example.com DocumentRoot "/var/www/html/server2" CustomLog "logs/access_log" combined ErrorLog "logs/error_log" <Directory "/var/www/html/server2"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> </VirtualHost> .....

#sudo systemctl restart httpd

 

  • php73 설치

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 remi repository를 yum 에 추가 한다. # wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm # rpm -Uvh epel-release-latest-7.noarch.rpm # wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm # rpm -Uvh remi-release-7.rpm # yum install -y yum-utils # yum-config-manager --enable remi-php73 기존의 설치된 PHP 패키지를 확인하여 잘못된 패키지가 삭제되지 않도록 한다. # yum list installed | cut -d " " -f 1 | grep php 기존 설치된 PHP를 제거. (php5) #yum remove -y `yum list installed | cut -d " " -f 1 | grep php` php 패키지 설치. php-common 외의 패키지는 자신의 상황에 맞게 조정해서 설치한다. # yum install -y php-common php-fpm php-cli \ php-process \ php-opcache php-pecl-apcu \ php-mysqlnd php-pdo \ php-gd \ php-mbstring php-xml \ php-pecl-zip \ php-bcmath #php -v PHP 7.3.34

 

  • mariadb 설치

#yum install mariadb mariadb-server 

#mysql --version
mysql Ver 15.1 Distrib 5.5.68-MariaDB, for Linux (x86_64) using readline 5.1

 

  • APM설정파일 경로

/etc/php.ini

/var/lib/php/

/etc/httpd/conf.d/php.conf

/etc/httpd/conf/httpd.conf

 

  • 명령어

-실행

sudo systemctl start httpd

sudo systemctl start mariadb

-확인

sudo systemctl status httpd

sudo systemctl status mariadb



[Algorithm] 힙 우선순위큐 [Heap Priority Queue] (더 맵게)


문제 ]

매운 것을 좋아하는 Leo는 모든 음식의 스코빌 지수를 K 이상으로 만들고 싶습니다. 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 Leo는 스코빌 지수가 가장 낮은 두 개의 음식을 아래와 같이 특별한 방법으로 섞어 새로운 음식을 만듭니다.

섞은 음식의 스코빌 지수 =  가장 맵지 않은 음식의 스코빌 지수 + (두 번째로 맵지 않은 음식의 스코빌 지수 * 2)

Leo가 가진 음식의 스코빌 지수를 담은 배열 scoville과 원하는 스코빌 지수 K가 주어질 때, 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 섞어야 하는 최소 횟수를 return 하도록 solution 함수를 작성해주세요.
제한 사항

  • scoville의 길이는 2 이상 1,000,000 이하입니다.
  • K는 0 이상 1,000,000,000 이하입니다.
  • scoville의 원소는 각각 0 이상 1,000,000 이하입니다.
  • 모든 음식의 스코빌 지수를 K 이상으로 만들 수 없는 경우에는 -1을 return 합니다.


입력

scovile = [1,2,3,9,10,12]
K = 7
출력
return 2

입출력 예 설명
  1. 스코빌 지수가 1인 음식과 2인 음식을 섞으면 음식의 스코빌 지수가 아래와 같이 됩니다. 새로운 음식의 스코빌 지수 = 1 + (2 * 2) = 5
    가진 음식의 스코빌 지수 = [5, 3, 9, 10, 12]

  2. 스코빌 지수가 3인 음식과 5인 음식을 섞으면 음식의 스코빌 지수가 아래와 같이 됩니다. 새로운 음식의 스코빌 지수 = 3 + (5 * 2) = 13
    가진 음식의 스코빌 지수 = [13, 9, 10, 12]

모든 음식의 스코빌 지수가 7 이상이 되었고 이때 섞은 횟수는 2회입니다. Leo는 모든 음식의 스코빌 지수가 K 이상이 될 때까지 반복하여 섞습니다.



제출 1 ] 

class Solution {
    public int solution(int[] scoville, int K) {
        int answer = 0;
        int result = 0;
        if(K==0) return 0;
        Arrays.sort(scoville);
        for(int i=0;i<scoville.length;i++){
            System.out.println(Arrays.toString(scoville));
            if(scoville[i]==0) return -1;
            if(scoville[i]<K){
                result = scoville[i]+(scoville[i+1]*2);
                if(result > scoville[i+2]) {
                    scoville[i+1]=scoville[i+2];
                    scoville[i+2]=result;    
                }
                answer++;
            } else {
                break;
            }
        }
        System.out.println(answer);
        return answer;
    }
}
몇 몇 테스트에서 타임아웃과 효율성테스트 실패.
결국 힙을 써야될 것같은데 자바의 Priority queue자료형쓰라는 문제였다.


[ Priority queue ]
큐의 구조를 가지면서 우선순위가 높은 엘리먼트가 먼저 poll되는 자료구조이다. 우선순위는 최대힙(내림차순)과 최소힙(오름차순)이 있으며 힙영역 메모리를 사용한다.












이진트리로 되어있으면 최대힙이면 root노드에 가장 큰 값, 
최소힙이면 root노드에 가장 작은 값이 들어간다.

기본적으로 import java.util.PriorityQueue; 를 임포트하고
PriorityQueue<제네릭> pq = new PriorityQueue<>(); 변수를 선언하여 사용한다. 

큐에 값을 추가하는 함수는
  • pq.add() / pq.offer()
큐에 값을 삭제하는 함수
  • pq.poll() // 첫번째 값(루트노드)을 반환하고 제거 비어있다면 null
  • pq.remove() // 첫번째 값 제거
  • pq.clear() // 우선순위 큐 초기화
출력 함수
  • pq.peek() // 우선순위 큐 첫번째 값 출력
  • pq.size() // number of elements present in the PriorityQueue


제출 2 ] 
import java.util.PriorityQueue;
class Solution {
public int solution(int[] scoville, int K) {
            PriorityQueue<Integer> pq = new PriorityQueue<>();
    int answer = 0;
        
            for (int i=0; i < scoville.length; i++){
                pq.add(scoville[i]);
            }

            while(pq.peek() < K){
                if (pq.size() < 2) return -1;
                int a = pq.poll();
        int b = pq.poll();
        pq.add(a + 2 * b);
        answer++;
            }
        return answer;
}
}



우선순위 큐 참조 : 
https://coding-factory.tistory.com/603



2020년 11월 22일 일요일

[Algorithm] 스택&큐 ( 주식가격 )


문제 ]

초 단위로 기록된 주식가격이 담긴 배열 prices가 매개변수로 주어질 때,

가격이 떨어지지 않은 기간은 몇 초인지를 return하시오.


- 입출력 예

prices : [ 1, 2, 3, 2, 3]

return : [ 4, 3, 1, 1, 0]




제출 ]

선택정렬 비스무리한 느낌이나서 이중 for문으로 해결하면 되지 않을까?

하는 생각으로 stack을 사용하지 않고 제출


class Solution {

    public int[] solution(int[] prices) {

        int len = prices.length;

        int[] answer = new int[len];


        for(int i=0; i<len; i++){

            for(int j=i+1; j<len; j++){

                answer[i]++;

                if (prices[i] > prices[j]){

                    break;

                }

            }

        }

        return answer;

    }

}



제출 2 ]

Stack을 이용한 다른분의 풀이


import java.util.Stack;

class Solution {

    public int[] solution(int[] prices) {

        Stack<Integer> beginIdxs = new Stack<>();

        int i=0;

        int[] terms = new int[prices.length];


        beginIdxs.push(i);

        for (i=1; i<prices.length; i++) {

            while (!beginIdxs.empty() && prices[i] < prices[beginIdxs.peek()]) {

                int beginIdx = beginIdxs.pop();

                terms[beginIdx] = i - beginIdx;

            }

            beginIdxs.push(i);

        }

        while (!beginIdxs.empty()) {

            int beginIdx = beginIdxs.pop();

            terms[beginIdx] = i - beginIdx - 1;

        }

        return terms;

    }

}


- Int형 제네릭 스택 선언, 스택함수로는

stack.push(obj) : 가장 탑에 데이터 추가

stack.pop() : 최근에 추가된 데이터 삭제

stack.peek() : 최근에 추가된 데이터 조회

stack.empty() : stack값이 비었는지 확인, 비면 True 아니면 False


 

2020년 11월 16일 월요일

Apache Kafka - 재시작시 meta.propertie 에러


에러메세지 ]

[2020-11-16 06:12:51,050] ERROR Fatal error during KafkaServer startup. Prepare to shutdown (kafka.server.KafkaServer)

kafka.common.InconsistentClusterIdException: The Cluster ID lTeGi4hnRaKFOHhVMQnfEg doesn't match stored clusterId Some(eaVbu41vRfSi-XzD7DxMog) in meta.properties. The broker is trying to join the wrong cluster. Configured zookeeper.connect may be wrong.

        at kafka.server.KafkaServer.startup(KafkaServer.scala:223)

        at kafka.server.KafkaServerStartable.startup(KafkaServerStartable.scala:44)

        at kafka.Kafka$.main(Kafka.scala:82)

        at kafka.Kafka.main(Kafka.scala)



원인 ]

해당파일을 찾아 열어보면

cat /mnt/data/kafka-logs/meta.propertie

    cluster.id=lTeGi4hnOodaKFOHhVMQnfEg

    version=0

    broker.id=1

와 같이 되어있는데,

정상적이지 않은 종료, 재시작으로 broker.id에 해당하는 cluster.id가 맞지 않아 생긴다.



해결 ]

해당 파일을 지우고 카프카 재시작한다.

sudo rm /mnt/data/kafka-logs/meta.propertie



[Algorithm] 해시맵 ( 완주하지 못한 선수 )

문제 ]

수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.

마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.


제한사항

  • 마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하입니다.
  • completion의 길이는 participant의 길이보다 1 작습니다.
  • 참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있습니다.
  • 참가자 중에는 동명이인이 있을 수 있습니다.



제출 ]

import java.util.Arrays;

class Solution {

    public String solution(String[] participant, String[] completion) {

        String answer = "";

        Arrays.sort(participant);

        Arrays.sort(completion);

        int i;

        for(i=0; i < completion.length; i++){

            if(!participant[i].equals(completion[i])){

                return participant[i];

            }

        }

        return participant[i];

    }

}



풀이 ]











사진출처 :https://medium.com/@nsh235482


Arrays.sort함수를 이용하여 두배열을 정렬하면 두가지의 경우가 생긴다.

1. 위 그림처럼 맨뒤에 완주하지 못한 사람이 남는 경우

2. 배열 처음~중간에 두 배열 값이 일치하지 않는 경우


(2)의 경우 for문을 통해 처리했고 (1)의 경우에는 for문이 끝난 후 i 값이 맨 마지막 배열의 인자를 가리키게되므로 마지막 return코드로 처리한다.


처음에는 int i를 for문에 (i=0; i < completion.length; i++) 처럼 선언하고 

마지막 리턴문을 retrun participant[participant.length -1] 로 작성했는데 위의 제출코드처럼 수정한 것이 더 깔끔해보인다.

문제를 처음 보고 해시맵문제인데 해시를 안써도 되겠단 생각이 들었지만, 문제 제출 후 다른 분들이 해시를 이용한 코드를 참고할 수 밖에 없었다.



제출 2 ]

import java.util.HashMap;

class Solution{

    public String solution(String[] participant, String[] completion) {

        String answer = "";

        HashMap<String, Integer> hm = new HashMap<>();

        for (String player : participant) hm.put(player, hm.getOrDefault(player, 0) +1);

        for (String player : completion) hm.put(player, hm.get(player) -1);

        

        for (String key : hm.keySet(0) {

           if (hm.get(key) != 0){

               answer = key;

            }

        }

        return answer;

    }

}



풀이 2 ]

participant배열 값들은 모두 1의 값을 가지는 맵을 정의한다.

ex ) 존 : 1, 잭: 1, 에밀리 : 1......

동명이인일 때는 +1을 한번더 하여 "존 : 2" 가 되도록한다. 


그 뒤 completion배열과 map의 키값을 비교하여 각 value -1을 한다.

ex ) 존 : 1, 잭 0, 에밀리 : 0 ....

결국 1이 남는 key값이 완주하지 못한 선수이다.


* for ( key value : map.keySet() ) : map의 iterator기능을 하는 for 문

* map.getOrDefault ( key, default value) : 찾는 키가 존재한다면 그 키값을 반환하고 없다면 기본값을 반환한다.

* HashMap 함수

  • put()
  • putAll()
  • get()
  • remove()
  • clear()
  • isEmpty()
  • keySet()
  • values()
  • containsKey()
  • containsValue()
  • replace()

 



2020년 11월 12일 목요일

Apache Nifi [2] - Queued 설정


Queued 우측클릭->구성설정 버튼을 클릭하면 아래와 같이
설정할 수 있는 창이나온다.





FlowFile Expiration

FlowFile Expiration은 특정기간에 쌓인 데이터들 중 처리할 수 없는 데이터를 자동으로 제거할 수 있는 개념이다. 예를 들어 큐의 데이터 볼륨이 초과할 것으로 예상됬을 때, 유통기한을 우선 순위자와 함께 사용하여 우선 순위가 가장 높은 데이터를 먼저 처리한 후 일정 기간(예: 1시간) 내에 처리할 수 없는 것은 모두 삭제할 수 있다. 

만료 기간은 데이터가 NiFi 인스턴스에 들어간 시간을 기준으로 한다. 즉, 특정 연결의 FlowFile Expiration가 '1시간'으로 설정되어 있고 NiFi 인스턴스에 1시간 동안 있었던 파일이 해당 연결에 도달하면 만료된다. 

기본값 0초는 데이터가 절대 만료되지 않음을 나타낸다. '0초' 이외의 파일 만료를 설정하면 연결 라벨에 작은 시계 아이콘이 나타나기 때문에 흐름을 한눈에 볼 수 있다.







Back pressure

NiFi는 Back Pressure를 위한 두 가지 구성 요소를 제공한다. 임계값은 원본 데이터소스가 대기열에 존재할 수 있는 데이터 양을 나타낸다. 이를 통해 시스템이 데이터 오버런을 방지할 수 있다. 

제공되는 첫 번째 옵션은 "Back pressure object threshold"이다. 이것은 Back pressure를 적용하기 전에 대기열에 포함될 수 있는 FlowFiles 수를 나타낸다. 

두 번째 구성 옵션은 "Back pressure 데이터 크기 임계값"이다. 이것은 Back pressure를 적용하기 전에 대기열에 넣어야 하는 최대 데이터 양(크기)을 지정한다. (바이트의 경우 B, 킬로바이트의 경우 KB, 메가바이트의 경우 MB, 기가바이트의 경우 GB 또는 테라바이트의 경우 TB)

기본적으로 새로 추가된 각 연결dml  기본 Back pressure설정 값은 임계값 10,000개와 데이터 크기 임계값 1GB이다. 

활성화되면 연결 라벨에 작은 진행 표시줄이 나타나므로 캔버스의 흐름을 볼 때 이를 한눈에 볼 수 있다. 대기열 백분율에 따라 진행률 표시줄의 색 변경: 녹색(0~60%), 황색(61~85%), 적색(86~100%) 등이었다.




Load Balancing (부하 분산 전략)

NiFi는 데이터의 흐름을 클러스터 노드 전체에 분산시키기 위해 다음과 같은 로드 밸런싱 전략을 제공한다.
























Do not load balance : 클러스터의 노드 간에 FlowFiles를 로드 밸런싱하지않는다(기본값).

Partition by attribute : 사용자 지정 FlowFile 특성의 값에 따라 데이터를 보낼 노드를 결정한다. 속성 값이 동일한 모든 FlowFiles는 클러스터의 동일한 노드로 전송된다. 대상 노드가 클러스터에서 분리되거나 통신할 수 없는 경우, 노드가 다시 사용 가능해질 때까지 기다린다. 

Round robin : FlowFiles는 라운드 로빈 방식으로 클러스터의 노드에 배포된다. 노드가 클러스터에서 분리되거나 노드와 통신할 수 없는 경우, 해당 노드에 대기 중인 데이터는 자동으로 다른 노드로 재분산된다. 노드가 클러스터의 다른 노드처럼 데이터를 빠르게 수신할 수 없는 경우, 클러스터 전체의 데이터 배포 처리량을 극대화하기 위해 노드를 하나 이상 반복하여 건너뛸 수도 있다.

Single node : 모든 FlowFiles는 클러스터의 단일 노드로 전송된다. 어떤 노드로 전송되는지는 구성할 수 없다. 노드가 클러스터에서 분리되거나 노드와 통신할 수 없는 경우, 해당 노드에 대해 대기 중인 데이터는 노드를 다시 사용할 수 있을 때까지 대기열에 남아 있게 된다.



연결에 대해 로드 밸런싱 전략을 실행한 경우 연결에 로드 밸런싱 표시기(Load Balance Icon)가 나타난다.












Available Prioritizers (우선 순위 지정)

첫번째 이미지 탭의 오른쪽은 더 높은 우선순위 데이터가 먼저 처리되도록 대기열에서 데이터의 우선순위를 지정할 수 있는 기능을 제공한다. 우선순위 지정자를 위에서 아래로 끌 수 있다. 






참고 : https://nifi.apache.org/docs/nifi-docs/html/user-guide.html

Apache Zeppelin [5] - 인증 및 접근권한 설정


제플린의 인증은 shiro.ini파일로 설정한다.


sudo cp /usr/local/zeppelin/conf/shiro.ini.template /usr/local/zeppelin/conf/shiro.ini

sudo vi /usr/local/zeppelin/conf/shiro.ini

sudo /usr/local/zeppelin/bin/zeppelin-daemon.sh restart


재시작후 웹페이지에서 제플린메인을 접속하면,

기존 anonymous계정으로 로그인과 인터프리터, 설정등 페이지에 접근이 불가능하다.



[ Shiro.ini Config ]

설정파일은 main, users, roles, urls와 같이 4파트로 나뉘는데 

각 파트별 설정내용은 다음과 같다.


[main] :Realm과 같은 Security Managerd의 object와 properties가 정의

[users] : 사용자 계정과 관련된 properties가 정의

[roles] : 계정의 roles와 관련된 설정값

[urls] : URL 기반 보안에 사용


* Realm

사용자, 역할 및 권한과 같은 애플리케이션별 보안 데이터에 액세스할 수 있는 구성 요소다. Realmssms 애플리케이션별 데이터를 Shiro가 이해한 형식으로 변환하여 데이터 소스가 얼마나 많든, 애플리케이션별로 어떻게 존재하든 Shiro가 이해하기 쉬운 단일 프로그래밍 API를 제공할 수 있도록 한다.

Realms는 관계형 데이터베이스, LDAP 디렉토리, 파일 시스템 또는 기타 유사한 리소스와 같은 데이터 소스와 1 대 1의 상관관계를 가진다. Realms의 인터페이스의 구현은 데이터 소스별 API를 사용하여 JDBC, 파일 IO, 최대 절전 모드 또는 JPA와 같은 권한 부여 데이터(역할, 권한 등)의 Data Access API를 제공한다.

참조 : http://shiro.apache.org/realm.html




1. MAIN

Active Directory 

activeDirectoryRealm = org.apache.zeppelin.realm.ActiveDirectoryGroupRealm
activeDirectoryRealm.systemUsername = userNameA
activeDirectoryRealm.systemPassword = passwordA
activeDirectoryRealm.hadoopSecurityCredentialPath = jceks://zeppelin/conf/zeppelin.jceks
activeDirectoryRealm.searchBase = CN=Users,DC=SOME_GROUP,DC=COMPANY,DC=COM
activeDirectoryRealm.url = ldap://ldap.test.com:389
activeDirectoryRealm.groupRolesMap = "CN=aGroupName,DC=COMPANY,DC=COM":"group1"
activeDirectoryRealm.authorizationCachingEnabled = false
activeDirectoryRealm.principalSuffix = @corp.company.net


LDAP

LDAP Realms를 구성하기 위해 가장 사용하기 쉬운 것은 LdapGroupRealm이다.

LDAP 그룹을 사용자에 매핑하고 사용자 그룹에 대한 권한 부여를 위한Realms 설정은 다음과 같다.

ldapRealm = org.apache.zeppelin.realm.LdapGroupRealm
# search base for ldap groups (only relevant for LdapGroupRealm):
ldapRealm.contextFactory.environment[ldap.searchBase] = dc=COMPANY,dc=COM
ldapRealm.contextFactory.url = ldap://ldap.test.com:389
ldapRealm.userDnTemplate = uid={0},ou=Users,dc=COMPANY,dc=COM
ldapRealm.contextFactory.authenticationMechanism = simple


PAM

PAM 인증 지원을 통해 제플린이 실행 중인 호스트에서 기존 인증 모듈을 재사용할 수 있다. 일반적인 시스템 모듈에서는 /etc/pam.d/에 따라 sshd, passwd 등의 서비스별로 구성된다. 이러한 서비스 중 하나를 재사용하거나 Zeppelin을 위해 자신만의 서비스를 만들 수 있다.

[main]
 pamRealm=org.apache.zeppelin.realm.PamRealm
 pamRealm.service=sshd



Secure Cookie for Zeppelin 세션

세션 쿠키에서 HttpOnly 플래그를 설정하도록 제플린을 구성할 수 있다. 이 구성으로 제플린 쿠키는 클라이언트 쪽 스크립트를 통해 액세스할 수 없으므로 대부분의 XSS(Cross-Site Scripting) 공격을 차단한다.

cookie = org.apache.shiro.web.servlet.SimpleCookie
cookie.name = JSESSIONID
cookie.secure = true
cookie.httpOnly = true
sessionManager.sessionIdCookie = $cookie

그 외에 ZeppelinHub, Knox SSo등의 Realm관련 설정을 할 수 있다.

참고 : https://zeppelin.apache.org/docs/0.8.0/setup/security/shiro_authentication.html#active-directory




2. USERS

Users 섹션에서는 정적 사용자 계정을 정의할 수 있다. 사용자 계정의 수가 매우 적거나 사용자 계정을 런타임에 동적으로 만들 필요가 없는 환경에서 유용하다.


위와 같이 설정포맷은 username = password, role1, role2 .... roleN 이다.

[users]

admin = 1234, admin

kail = pwd1, role1

jack = pwd2, role2, role3


users파트 암호를 일반 텍스트로 만들지 않으려면 해시 알고리즘(MD5, Sah1, Sah256 등)을 사용하여 암호화할 수 있다. 기본적으로 암호 문자열은 Hex 인코딩이며, Base64 인코딩으로도 구성할 수 있다.




3. ROLES

Roles파트의 예시는 아래와 같다.

[roles]
admin = *
hr = *
finance = *
group1 = *




4. URLS

기본적으로 user파트에 정의된 모든 사용자는 아파치 제플린의 인터프리터 설정, 인증 정보 및 구성 정보를 공유할 수 있다. 경우에 따라 사용 사례를 위해 이러한 정보페이지를 숨기고 싶을 수 있다. 

Shiro는 URL 기반 보안을 제공하므로 conf/shiro.ini에서 아래 줄에 주석을 달거나 압축을 해제하여 정보를 숨길 수 있다.


변경전

[urls]

/api/interpreter/** = authc, roles[admin]
/api/configurations/** = authc, roles[admin]
/api/credential/** = authc, roles[admin]


변경후

[urls]

/api/interpreter/** = roles[admin]
/api/configurations/** = roles[admin]
/api/credential/** = roles[admin]


위와 같이 설정하면 admin roles가 아닌 모든 계정은 Interpreter, Configuration, Credential 페이지 접근이 불가하다.















[ zeppelin permission ]

각 노트마다 접근권한을 지정해주어 해당노트의 crontab이나 쿼리, 대쉬보드 추가 삭제 등 유저마다 노트에 대한 권한을 달리 줄 수 있다.

아래 이미지와 같이 우측상단의 자물쇠 그림을 눌러 설정한다.









예를 들어 user1이 Note1을 Read만하고 쿼리실행이나 다른 작업을 못하게 하려면 Owners설정은 admin, Reader는 user1으로 설정한다.( Writers랑 Runners는 자동으로 Owners설정값을 따른다.)

또한 다른유저 user2는 Readers권한도 없으므로 로그인해도 해당 Note1이 보이지 않는다.


Readers권한이 있는 User가 다른 권한접근시 알림 메세지가 나온다.








결과적으로 제플린의 인증과 접근권한은 Shiro.ini파일의 users, roles, urls파트 설정과 자물쇠버튼의 Permission설정으로 어느 정도 가능하다. 그러나 유저가 많아 파생되는 그룹이 커지고 동적 유저또한 필요하다면 Realms manager 설정또한 추가되야 할 것이다.