Spring Cloud Config Server가 있는 EC2에 사용 가능한 용량이 없다는 문제로 해당 서버가 정상 동작하지 않자 해당 서버를 통해 설정 파일을 주입받는 모든 서버에 영향이..^^

용량이 이렇게 부족해 진 것은 불필요한 Batch작업이 해당 EC2에서 진행되고 있어서였고, 이는 처리하였다.

하지만 용량이 너무 작은 것으로 설정된 것 같긴 해서 이참에 볼륨 크기를 확장하기로.

 

아래 명령어로 파일시스템 용량을 확인해보았다. 

$ df -h

결과는 아래와 같았다. 

Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        978M     0  978M   0% /dev
tmpfs           986M     0  986M   0% /dev/shm
tmpfs           986M  101M  886M  11% /run
tmpfs           986M     0  986M   0% /sys/fs/cgroup
/dev/xvda1      8.0G  8.0G   20K 100% /
tmpfs           198M     0  198M   0% /run/user/1000
tmpfs           198M     0  198M   0% /run/user/0

AWS Console에서 해당 EC2의 스토리지의 볼륨디바이스를 보니 볼륨크기가 8Gib에 /dev/xvda로 설정되어 있는 것을 확인할 수 있었다. 

 

AWS Console에서 EBS Volume을 2배 (16Gib)로 변경해주었고, 아래 명령어로 연결된 블록 디바이스를 확인해보았다.

$ lsblk

루트 볼륨은 2배로 잘 커져 있었지만 파티션인 xvda1은 여전히 8Gib인 것을 볼 수 있을 것이다.

해당 파티션도 늘려주기 위해서 아래 명령어를 입력하였다 . 

$ sudo growpart /dev/xvda 1

그랬더니 아래와 같은 에러가...

mkdir: cannot create directory ‘/tmp/growpart.4699’: No space left on device
FAILED: failed to make temp dir

 

AWS 문서에 이와 같은 상황에서 할 수 있는 해결책을 제시해주었다. 


블록 디바이스에 남은 공간 없음 오류를 방지하려면 임시 파일 시스템 tmpfs /tmp 탑재 지점에 탑재합니다. 그러면 /tmp에 탑재된 10M tmpfs가 생성됩니다.

$ sudo mount -o size=10M,rw,nodev,nosuid -t tmpfs tmpfs /tmp

위와 같이 진행하고 아래 명령어를 입력하니 성공!

$ sudo growpart /dev/xvda 1
CHANGED: partition=1 start=4096 old: size=16773087 end=16777183 new: size=33550303 end=33554399

 

여기까지는 파티션의 크기를 늘린 것이고,

이제는 파일시스템에 변경된 파티션 크기를 적용해야 한다. 

그래서 아래의 명령어를 통해 적용해보려 했지만 에러가 뙇

$ sudo resize2fs /dev/xvda1

resize2fs 1.42.9 (28-Dec-2013)
resize2fs: Bad magic number in super-block while trying to open /dev/xvda1
Couldn't find valid filesystem superblock.

 

원인을 찾아보니 리눅스의 파일 시스템이 xfs라서 그런거라고 한다.. 아래 명령어를 입력해서 확인해 볼 수 있다. 

$ df -Th
Filesystem     Type      Size  Used Avail Use% Mounted on
devtmpfs       devtmpfs  978M     0  978M   0% /dev
tmpfs          tmpfs     986M     0  986M   0% /dev/shm
tmpfs          tmpfs     986M  101M  886M  11% /run
tmpfs          tmpfs     986M     0  986M   0% /sys/fs/cgroup
/dev/xvda1     xfs       8.0G  8.0G   20K 100% /
tmpfs          tmpfs     198M     0  198M   0% /run/user/1000
tmpfs          tmpfs     198M     0  198M   0% /run/user/0
tmpfs          tmpfs      10M     0   10M   0% /tmp

/dev/xvda1의 Type이 xfs로 되어 있다.  리눅스의 파일 시스템이 xfs일 경우 발생한다고 한다. 

 

이럴때는 resize2fs가 아닌 xfs_growfs를 써야 한다.

$ sudo xfs_growfs /dev/xvda1

아래의 메시지와 함께 정보들이 나열되면 성공!!

data blocks changed from 2096635 to 4193787

 

df -Th로 확인해보면~

Filesystem     Type      Size  Used Avail Use% Mounted on
devtmpfs       devtmpfs  978M     0  978M   0% /dev
tmpfs          tmpfs     986M     0  986M   0% /dev/shm
tmpfs          tmpfs     986M  100M  887M  11% /run
tmpfs          tmpfs     986M     0  986M   0% /sys/fs/cgroup
/dev/xvda1     xfs        16G  8.1G  8.0G  51% /
tmpfs          tmpfs     198M     0  198M   0% /run/user/1000
tmpfs          tmpfs     198M     0  198M   0% /run/user/0
tmpfs          tmpfs      10M     0   10M   0% /tmp

/dev/xvda1의 Size가 16G이고 Use%가 100%에서 51%로 줄어있는 것을 확인할 수 있다.

 

 

 

용량이 어느새 다시 찼다...

알고 보니 log 디렉토리에 로그파일이 수두룩 빽빽하게 쌓여서 용량을 다 잡아 먹고 있었던 것이다.

그래서 근본적인 해결을 하기로 하였고.

$ sudo du --/ | sort -| tail -40 | sort --r

위 명령어를 통해 용량 차지 상위 순서대로 디렉토리 리스트를 뽑아봤고,

거기서 로그 디렉토리가 압도적인 것을 확인. 

스크립트를 짜서 15일에 한번씩 로그 파일들을 정리하기로 했다. 

 

 

끝!

 

 

 

출처

https://aws.amazon.com/ko/premiumsupport/knowledge-center/ebs-volume-size-increase/

https://velog.io/@hyeonseop/ec2-%EC%9A%A9%EB%9F%89-full%EC%9D%BC-%EB%95%8C-%EB%8C%80%EC%B2%98%EB%B2%95

https://nirsa.tistory.com/231

타 부서에서 현재 개발하고 있는 플랫폼에서 사용자 관리 부분을 따로 관리하고 싶다고 하였다.

그 관리는 SCIM 방식으로 하길 원했고, 나는 이에 따라 SCIM API Endpoint를 제공하기로 하였다....

(서비스 오픈을 앞두고 개인적으로 좀 진행하고 있던게 있었는데 그걸 멈추고 해야 했던지라 솔직히 하기 싫었다..ㅠㅠ....)

 

 

  • SCIM
    • 클라우드 기반 애플리케이션 및 서비스에서 사용자 ID를 보다 쉽게 ​​관리할 수 있도록 설계된 것
    • 사용자 관리에 들어가는 비용과 복잡성을 줄이고자 하는 목적으로 개발되어 SCIM은 공통 사용자 스키마 및 확장 모델을 제공하고 REST API를 통해 이 스키마를 교환하기 위한 패턴을 제공하는 바인딩 문서를 제공합니다.
  • SCIM Schema Structure
    • SCIM 스키마는 많은 기존 배포 및 스키마에서 발견되는 공통 속성을 포함하는 사용자 및 그룹(리소스)을 나타내기 위한 최소 핵심 스키마를 제공합니다.
    • Resource은 하나 이상의 스키마로 식별되는 속성 모음입니다. 속성은 이름과 하나 이상의 단순 또는 복합 값으로 구성됩니다. SCIM 스키마는 속성의 데이터 유형, 복수 및 기타 구별되는 기능을 정의합니다. 달리 지정되지 않는 한 모든 속성은 소비자가 수정할 수 있습니다. 불변(읽기 전용) 속성은 속성 정의 내에서 'READ-ONLY'로 지정되어야 합니다(SHALL). 
  • Model
    • SCIM 2.0은 리소스가 공통 분모이고 모든 SCIM 개체가 리소스에서 파생되는 개체 모델을 기반으로 합니다.
    • id, externalId, meta를 속성으로 갖고 RFC7643은 공통 속성을 확장한 User, Group, EnterpriseUser를 정의한다.

  • Schema Extenstion Model
    • SCIM 스키마는 LDAP에서 사용되는 ObjectClasses와 유사한 개체 확장 모델을 따릅니다. LDAP와 달리 상속 모델이 없습니다. 모든 확장은 추가됩니다. 스키마 확장은 공통 정의된 속성을 재정의해서는 안 되며 이 사양에 정의된 규칙을 따라야 합니다(SHOULD). 각 스키마 확장은 확장을 식별하는 데 사용되는 URI를 식별해야 합니다. XML은 XML 네임스페이스를 사용해야 하고 JSON 형식은 확장 리소스와 속성을 구별하기 위해 "스키마" 속성을 사용해야 합니다(MUST).
      • LDAP : 경량 디렉터리 액세스 프로토콜은 TCP/IP 위에서 디렉터리 서비스를 조회하고 수정하는 응용 프로토콜
  • SCIM Core Schema
    • 각 SCIM 리소스(사용자, 그룹 등)에는 다음과 같은 공통 속성이 포함됩니다. 이러한 속성은 확장된 리소스 유형을 포함하여 모든 리소스에 포함되어야 합니다. 핵심 스키마가 암시적으로 포함되어 있으므로 이 문서에서 리소스가 완전히 정의된 경우 schema 속성을 지정할 필요가 없습니다. 
    • Common Schema Attributes
      • id
        • 서비스 공급자가 정의한 SCIM 리소스의 고유 식별자입니다. 리소스의 각 표현은 비어 있지 않은 id 값을 포함해야 합니다(MUST). 이 식별자는 서비스 제공자의 전체 리소스 집합에서 고유해야 합니다(MUST). id 속성의 값은 항상 서비스 제공자에 의해 발행되며 서비스 소비자에 의해 지정되어서는 안 됩니다(MUST). 
      • externalId
        • 서비스 소비자가 정의한 리소스의 식별자입니다. externalId는 소비자가 자체 식별자로 리소스를 참조할 수 있도록 하여 서비스 소비자와 서비스 제공자 간의 리소스 식별을 단순화할 수 있습니다. 공급자. 각 리소스는 비어 있지 않은 externalId 값을 포함할 수 있습니다(MAY). externalId 속성의 값은 항상 서비스 소비자로 발행되며 서비스 공급자가 지정할 수 없습니다. 
      • meta
        • 리소스 메타데이터를 포함하는 복합 속성입니다. 모든 하위 속성은 선택 사항입니다.
        • created
          • 리소스가 서비스 공급자에 추가된 DateTime입니다. 속성은 DateTime이어야 합니다. 읽기 전용.
        • lastModified
          • 이 리소스가 최초 생성 이후 수정된 적이 없는 경우 값은 생성된 값과 동일해야 합니다(MUST). 속성은 DateTime이어야 합니다. 읽기 전용.
        • location
          • 반환되는 리소스의 URI입니다. 이 값은 Location HTTP 응답 헤더와 동일해야 합니다(MUST). 읽기 전용.
        • version
          • 반환되는 리소스의 버전입니다. 이 값은 ETag HTTP 응답 헤더와 동일해야 합니다. 읽기 전용.
        • attributes
          • PATCH 작업 동안 리소스에서 제거할 속성의 이름입니다.
  • "schema" Attribute
    • SCIM은 확장 가능한 스키마와 함께 다양한 유형의 리소스를 지원합니다. 각 리소스는 정규화된 URL을 사용하여 표시되어야 합니다(MUST). 특정 표현에 스키마 표현에 대한 기존 지원이 있는 경우 해당 표현의 전통적인 규칙을 적용해야 합니다(MUST). 예를 들어 XML을 사용하여 사용자를 나타낼 때는 XML Namespace를 사용해야 합니다.
    • schemas
      • schemas 속성은 SCIM 표현에 대해 지원되는 스키마 버전과 해당 표현이 지원하는 모든 스키마 확장을 검사할 수 있는 문자열 배열입니다. 각 문자열 값은 고유한 URI여야 합니다. 이 사양은 사용자, 그룹 및 표준 "엔터프라이즈" 확장에 대한 URI를 정의합니다. SCIM 스키마의 모든 표현은 해당 표현에서 지원하는 URI 값과 함께 0이 아닌 값 배열을 포함해야 합니다(MUST). 중복 값은 포함되어서는 안 됩니다(MUST NOT). 값 순서가 지정되지 않았으며 동작에 영향을 주어서는 안 됩니다(MUST). 필수의.
  • SCIM User Schema
    • SCIM은 'urn:scim:schemas:core:1.0' URI를 사용하여 식별되는 사용자를 나타내는 스키마를 제공합니다. SCIM 핵심 스키마에 정의된 속성 외에 다음 속성이 정의됩니다.
      • userName, name, displayName, nickName, profileUrl, title, userType, preferredLanguage, locale, timezone, active, password
  • SCIM Enterprise User Schema Extension
    • 다음 SCIM 확장은 비즈니스 또는 기업에 속하거나 이를 대신하는 사용자를 나타내는 데 일반적으로 사용되는 속성을 정의합니다. 엔터프라이즈 사용자 확장은 'urn:scim:schemas:extension:enterprise:1.0' URI를 사용하여 식별됩니다.
      • employeeNumber, costCenter, organization, division, department, manager (managerId, displayName)
  • SCIM Group Schema
    • SCIM은 'urn:scim:schemas:core:1.0' URI를 사용하여 식별되는 그룹을 나타내는 스키마를 제공합니다. 그룹 리소스는 명시적인 권한 부여 모델이 정의되어 있지 않더라도 공통 그룹 또는 역할 기반 액세스 제어 모델의 표현을 가능하게 하기 위한 것입니다. 
    • SCIM 핵심 스키마에 정의된 공통 속성에 추가로 다음의 단일 속성이 정의됩니다.
      • displayName : 사람이 읽을 수 있는 그룹 이름입니다. (REQUIRED)
    • SCIM 핵심 스키마에 정의된 공통 속성 외에 다음 다중값 속성이 정의됩니다.
      • members : 그룹의 구성원 목록입니다. 표준 유형 "사용자" 및 "그룹"은 읽기 전용입니다. 값은 SCIM 리소스의 "id"(사용자 또는 그룹)여야 합니다. 그룹 유형의 의도는 서비스 공급자가 중첩된 그룹을 지원할 수 있도록 하는 것입니다.
  • Service Provider Configuration Schema
    • SCIM은 'urn: scim: schemas: core: 1.0' URI를 사용하여 식별된 서비스 제공자의 구성을 나타내는 스키마를 제공합니다.
    • 서비스 공급자 구성 리소스를 사용하면 서비스 공급자가 SCIM 사양 준수를 표준화된 형식으로 노출할 수 있을 뿐만 아니라 추가 구현 세부 정보를 소비자에게 제공할 수 있습니다. 모든 속성은 읽기 전용입니다.
    • Core Schema에 정의된 공통 속성 외에 다음의 단일 속성이 정의됩니다.
  • Resource Schema
    • 리소스 스키마는 리소스를 구성하는 속성과 메타데이터를 지정합니다. Resources 스키마는 읽기 전용이며 URI 'urn:scim:schemas:core:1.0'을 사용하여 식별됩니다. 다른 핵심 자원과 달리 Resources 스키마는 하위 속성 내에 복합 객체를 포함할 수 있으며 다른 속성이 지정되지 않는 한 모든 속성은 필수입니다.
    • Attributes로는 일단  name, description, schema, endpoint 등등이 있음

 


JSON Representation

 

Minimal User Representation

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "id": "2819c223-7f76-453a-919d-413861904646",
  "userName": "bjensen@example.com",
  "meta": {
    "resourceType": "User",
    "created": "2010-01-23T04:56:22Z",
    "lastModified": "2011-05-13T04:42:34Z",
    "version": "W\/\"3694e05e9dff590\"",
    "location":
     "https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646"
  }
}

 

 

Full User Representation(더보기를 클릭해서 확인하시면 됩니다)

더보기
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "id": "2819c223-7f76-453a-919d-413861904646",
  "externalId": "701984",
  "userName": "bjensen@example.com",
  "name": {
    "formatted": "Ms. Barbara J Jensen, III",
    "familyName": "Jensen",
    "givenName": "Barbara",
    "middleName": "Jane",
    "honorificPrefix": "Ms.",
    "honorificSuffix": "III"
  },
  "displayName": "Babs Jensen",
  "nickName": "Babs",
  "profileUrl": "https://login.example.com/bjensen",
  "emails": [
    {
      "value": "bjensen@example.com",
      "type": "work",
      "primary": true
    },
    {
      "value": "babs@jensen.org",
      "type": "home"
    }
  ],
  "addresses": [
    {
      "type": "work",
      "streetAddress": "100 Universal City Plaza",
      "locality": "Hollywood",
      "region": "CA",
      "postalCode": "91608",
      "country": "USA",
      "formatted": "100 Universal City Plaza\nHollywood, CA 91608 USA",
      "primary": true
    },
    {
      "type": "home",
      "streetAddress": "456 Hollywood Blvd",
      "locality": "Hollywood",
      "region": "CA",
      "postalCode": "91608",
      "country": "USA",
      "formatted": "456 Hollywood Blvd\nHollywood, CA 91608 USA"
    }
  ],
  "phoneNumbers": [
    {
      "value": "555-555-5555",
      "type": "work"
    },
    {
      "value": "555-555-4444",
      "type": "mobile"
    }
  ],
  "ims": [
    {
      "value": "someaimhandle",
      "type": "aim"
    }
  ],
  "photos": [
    {
      "value":
        "https://photos.example.com/profilephoto/72930000000Ccne/F",
      "type": "photo"
    },
    {
      "value":
        "https://photos.example.com/profilephoto/72930000000Ccne/T",
      "type": "thumbnail"
    }
  ],
   "userType": "Employee",
  "title": "Tour Guide",
  "preferredLanguage": "en-US",
  "locale": "en-US",
  "timezone": "America/Los_Angeles",
  "active":true,
  "password": "t1meMa$heen",
  "groups": [
    {
      "value": "e9e30dba-f08f-4109-8486-d5c6a331660a",
      "$ref":
"https://example.com/v2/Groups/e9e30dba-f08f-4109-8486-d5c6a331660a",
      "display": "Tour Guides"
    },
    {
      "value": "fc348aa8-3835-40eb-a20b-c726e15c55b5",
      "$ref":
"https://example.com/v2/Groups/fc348aa8-3835-40eb-a20b-c726e15c55b5",
      "display": "Employees"
    },
    {
      "value": "71ddacd2-a8e7-49b8-a5db-ae50d0a5bfd7",
      "$ref":
"https://example.com/v2/Groups/71ddacd2-a8e7-49b8-a5db-ae50d0a5bfd7",
      "display": "US Employees"
    }
  ],
    "x509Certificates": [
    {
      "value":
       "MIIDQzCCAqygAwIBAgICEAAwDQYJKoZIhvcNAQEFBQAwTjELMAkGA1UEBhMCVVMx
        EzARBgNVBAgMCkNhbGlmb3JuaWExFDASBgNVBAoMC2V4YW1wbGUuY29tMRQwEgYD
        VQQDDAtleGFtcGxlLmNvbTAeFw0xMTEwMjIwNjI0MzFaFw0xMjEwMDQwNjI0MzFa
        MH8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQKDAtl
        eGFtcGxlLmNvbTEhMB8GA1UEAwwYTXMuIEJhcmJhcmEgSiBKZW5zZW4gSUlJMSIw
        IAYJKoZIhvcNAQkBFhNiamVuc2VuQGV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0B
        AQEFAAOCAQ8AMIIBCgKCAQEA7Kr+Dcds/JQ5GwejJFcBIP682X3xpjis56AK02bc
        1FLgzdLI8auoR+cC9/Vrh5t66HkQIOdA4unHh0AaZ4xL5PhVbXIPMB5vAPKpzz5i
        PSi8xO8SL7I7SDhcBVJhqVqr3HgllEG6UClDdHO7nkLuwXq8HcISKkbT5WFTVfFZ
        zidPl8HZ7DhXkZIRtJwBweq4bvm3hM1Os7UQH05ZS6cVDgweKNwdLLrT51ikSQG3
        DYrl+ft781UQRIqxgwqCfXEuDiinPh0kkvIi5jivVu1Z9QiwlYEdRbLJ4zJQBmDr
        SGTMYn4lRc2HgHO4DqB/bnMVorHB0CC6AV1QoFK4GPe1LwIDAQABo3sweTAJBgNV
        HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp
        Y2F0ZTAdBgNVHQ4EFgQU8pD0U0vsZIsaA16lL8En8bx0F/gwHwYDVR0jBBgwFoAU
        dGeKitcaF7gnzsNwDx708kqaVt0wDQYJKoZIhvcNAQEFBQADgYEAA81SsFnOdYJt
        Ng5Tcq+/ByEDrBgnusx0jloUhByPMEVkoMZ3J7j1ZgI8rAbOkNngX8+pKfTiDz1R
        C4+dx8oU6Za+4NJXUjlL5CvV6BEYb1+QAEJwitTVvxB/A67g42/vzgAtoRUeDov1
        +GFiBZ+GNF/cAYKcMtGcrs2i97ZkJMo="
    }
  ],
  "meta": {
    "resourceType": "User",
    "created": "2010-01-23T04:56:22Z",
    "lastModified": "2011-05-13T04:42:34Z",
    "version": "W\/\"a330bc54f0671c9\"",
    "location":
"https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646"
  }
}

 

 

Enterprise User Extension Representation (더보기를 클릭해서 확인하시면 됩니다)

-extension을 추가한 예시임, schemas를 보면 배열에 2개의 스키마가 정의되어 있다. 

더보기
{
  "schemas":
    ["urn:ietf:params:scim:schemas:core:2.0:User",
      "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],
  "id": "2819c223-7f76-453a-919d-413861904646",
  "externalId": "701984",
  "userName": "bjensen@example.com",
  "name": {
    "formatted": "Ms. Barbara J Jensen, III",
    "familyName": "Jensen",
    "givenName": "Barbara",
    "middleName": "Jane",
    "honorificPrefix": "Ms.",
    "honorificSuffix": "III"
  },
  "displayName": "Babs Jensen",
  "nickName": "Babs",
  "profileUrl": "https://login.example.com/bjensen",
  "emails": [
    {
      "value": "bjensen@example.com",
      "type": "work",
      "primary": true
    },
    {
      "value": "babs@jensen.org",
      "type": "home"
    }
  ],
  "addresses": [
    {
      "streetAddress": "100 Universal City Plaza",
      "locality": "Hollywood",
      "region": "CA",
      "postalCode": "91608",
      "country": "USA",
      "formatted": "100 Universal City Plaza\nHollywood, CA 91608 USA",
      "type": "work",
      "primary": true
    },
    
    {
      "streetAddress": "456 Hollywood Blvd",
      "locality": "Hollywood",
      "region": "CA",
      "postalCode": "91608",
      "country": "USA",
      "formatted": "456 Hollywood Blvd\nHollywood, CA 91608 USA",
      "type": "home"
     }
  ],
  "phoneNumbers": [
    {
      "value": "555-555-5555",
      "type": "work"
    },
    {
      "value": "555-555-4444",
      "type": "mobile"
    }
  ],
  "ims": [
    {
      "value": "someaimhandle",
      "type": "aim"
    }
  ],
  "photos": [
    {
      "value":
        "https://photos.example.com/profilephoto/72930000000Ccne/F",
      "type": "photo"
    },
    {
      "value":
        "https://photos.example.com/profilephoto/72930000000Ccne/T",
      "type": "thumbnail"
    }
  ],
   "userType": "Employee",
  "title": "Tour Guide",
  "preferredLanguage": "en-US",
  "locale": "en-US",
  "timezone": "America/Los_Angeles",
  "active":true,
  "password": "t1meMa$heen",
  "groups": [
    {
      "value": "e9e30dba-f08f-4109-8486-d5c6a331660a",
      "$ref": "../Groups/e9e30dba-f08f-4109-8486-d5c6a331660a",
      "display": "Tour Guides"
    },
    {
      "value": "fc348aa8-3835-40eb-a20b-c726e15c55b5",
      "$ref": "../Groups/fc348aa8-3835-40eb-a20b-c726e15c55b5",
      "display": "Employees"
    },
    {
      "value": "71ddacd2-a8e7-49b8-a5db-ae50d0a5bfd7",
      "$ref": "../Groups/71ddacd2-a8e7-49b8-a5db-ae50d0a5bfd7",
      "display": "US Employees"
    }
  ],
  "x509Certificates": [
    {
      "value":
       "MIIDQzCCAqygAwIBAgICEAAwDQYJKoZIhvcNAQEFBQAwTjELMAkGA1UEBhMCVVMx
        EzARBgNVBAgMCkNhbGlmb3JuaWExFDASBgNVBAoMC2V4YW1wbGUuY29tMRQwEgYD
        VQQDDAtleGFtcGxlLmNvbTAeFw0xMTEwMjIwNjI0MzFaFw0xMjEwMDQwNjI0MzFa
        MH8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQKDAtl
        eGFtcGxlLmNvbTEhMB8GA1UEAwwYTXMuIEJhcmJhcmEgSiBKZW5zZW4gSUlJMSIw
        IAYJKoZIhvcNAQkBFhNiamVuc2VuQGV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0B
        AQEFAAOCAQ8AMIIBCgKCAQEA7Kr+Dcds/JQ5GwejJFcBIP682X3xpjis56AK02bc
        1FLgzdLI8auoR+cC9/Vrh5t66HkQIOdA4unHh0AaZ4xL5PhVbXIPMB5vAPKpzz5i
        PSi8xO8SL7I7SDhcBVJhqVqr3HgllEG6UClDdHO7nkLuwXq8HcISKkbT5WFTVfFZ
        zidPl8HZ7DhXkZIRtJwBweq4bvm3hM1Os7UQH05ZS6cVDgweKNwdLLrT51ikSQG3
        DYrl+ft781UQRIqxgwqCfXEuDiinPh0kkvIi5jivVu1Z9QiwlYEdRbLJ4zJQBmDr
        SGTMYn4lRc2HgHO4DqB/bnMVorHB0CC6AV1QoFK4GPe1LwIDAQABo3sweTAJBgNV
        HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp
        Y2F0ZTAdBgNVHQ4EFgQU8pD0U0vsZIsaA16lL8En8bx0F/gwHwYDVR0jBBgwFoAU
        dGeKitcaF7gnzsNwDx708kqaVt0wDQYJKoZIhvcNAQEFBQADgYEAA81SsFnOdYJt
        Ng5Tcq+/ByEDrBgnusx0jloUhByPMEVkoMZ3J7j1ZgI8rAbOkNngX8+pKfTiDz1R
        C4+dx8oU6Za+4NJXUjlL5CvV6BEYb1+QAEJwitTVvxB/A67g42/vzgAtoRUeDov1
        +GFiBZ+GNF/cAYKcMtGcrs2i97ZkJMo="
    }
  ],
    "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
    "employeeNumber": "701984",
    "costCenter": "4130",
    "organization": "Universal Studios",
    "division": "Theme Park",
    "department": "Tour Operations",
    "manager": {
      "value": "26118915-6090-4610-87e4-49d8ca9f808d",
      "$ref": "../Users/26118915-6090-4610-87e4-49d8ca9f808d",
      "displayName": "John Smith"
    }
  },
  "meta": {
    "resourceType": "User",
    "created": "2010-01-23T04:56:22Z",
    "lastModified": "2011-05-13T04:42:34Z",
    "version": "W\/\"3694e05e9dff591\"",
    "location":
"https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646"
  }
}

 

Example User 

이것은 자바 어플리케이션 내에서 사용자 데이터를 SCIM 객체로 변환하는 방법으로 제가 사용한 코드의 예시입니다. 
@Getter
@Setter
public class ScimUser extends BaseModel {
    private String schema = "urn:ietf:params:scim:schemas:core:2.0:User";
    private UUID id;
    private String userName;
    private List<ScimEmailAttributes> emails;
    private Boolean active = false;
    private Boolean externalTestField = false;
    private String created;
    private String lastModified;

    public ScimUser(){
    }

    public ScimUser(User user){
        this.update(user);
    }

    public void update(User user) {
        this.id = UUID.nameUUIDFromBytes(user.getEmail().getBytes(StandardCharsets.UTF_8));
        this.userName = user.getUserName();
        this.active = user.isEnabled();
        this.externalTestField = user.externalTestField();
        ScimEmailAttributes attributes = new ScimEmailAttributes();
        attributes.setValue(user.getEmail());
        this.emails = Arrays.asList(attributes);
        this.created = ""; // 유저 데이터 생성 날짜 입력
        this.lastModified = ""; // 유저 데이터 수정 날짜 입력
    }


    @Override
    public Map<String, Object> toScimResource(){
        Map<String, Object> returnValue = new LinkedHashMap<>();

        ScimExternalTestDetail externalTestDetail = new ScimExternalTestDetail(); // User에서 Custom하게 추가할 필드를 위해 스키마를 추가한다.

        returnValue.put("schemas", Arrays.asList(this.schema, externalTestDetail.getSchemas()));
        returnValue.put("id", this.id);
        returnValue.put("userName", this.userName);
        returnValue.put("emails", this.emails);
        returnValue.put("active", this.active);

        // Meta information
        Map<String, Object> meta = new HashMap<>();
        meta.put("resourceType", "User");
        meta.put("location", ("scim/v1/Users"));
        meta.put("created", this.created);
        meta.put("lastModified", this.lastModified);
        returnValue.put("meta", meta);

		// Custom 필드 추가
        externalTestDetail.setExternalTestField(this.externalTestField); 
        returnValue.put(externalTestDetail.getSchemas(), externalTestDetail.toScimResource());

        return returnValue;
    }
}

 

생성

 

@Getter
@Setter
public class CreateTest {
    @JsonProperty("schemas")
    private List<String> schemas;
    @JsonProperty("userName")
    private String userName;
    @JsonProperty("emails")
    private List<ScimEmailAttributes> emails;
    @JsonProperty("urn:ietf:params:scim:schemas:extension:test:ExternalTestDetail:2.0")
    private ExternalTestDetail extenalTestDetail;
}
 
RequestBody
{
	"schemas": [
		"urn:ietf:params:scim:schemas:core:2.0:User",
		"urn:ietf:params:scim:schemas:extension:test:ExternalTestDetail:2.0"
	],
	"userName": "test",
	"emails": [
		{
			"value": "test@naver.com"
		}
	],
	"urn:ietf:params:scim:schemas:extension:test:ExternalTestDetail:2.0": {
		"extenalTestDetail": false
	}
}
 

ResponseBody

{
	"schemas": [
		"urn:ietf:params:scim:schemas:core:2.0:User",
		"urn:ietf:params:scim:schemas:extension:test:ExternalTestDetail:2.0"
	],
	"id": "7d0d8b63-ce15-36b3-b9c7-e8ca82e89b5c",
	"userName": "테스트유저",
	"emails": [
		{
			"value": "test@naver.com"
		}
	],
	"active": true,
	"meta": {
		"created": "",
		"location": "scim/v1/Users",
		"lastModified": "",
		"resourceType": "User"
	},
	"urn:ietf:params:scim:schemas:extension:test:ExternalTestDetail:2.0": {
		"externalTestField": false
	}
}
 
검색

User 검색의 경우에는 아래와 같이 작성하였습니다.

먼저 GET 방식으로 아래의 Request URL을 받습니다.

 

https://test.com/scim/v1/Users?filter=emails[value co "test@"]

SCIM 에서 제시하는 방법에 따라 'co (consist)'를 사용하였고, email로 검색하는 경우의 예입니다. 

검색결과는 JSON으로 아래와 같이 전달합니다.

schemas 내요을 보면 ListResponse인 것을 확인하실 수 있습니다. 

 

ResponseBody

{
	"schemas": [
		"urn:ietf:params:scim:api:messages:2.0:ListResponse"
	],
	"totalResults": 1,
	"Resources": [
		{
			"schemas": [
            "urn:ietf:params:scim:schemas:core:2.0:User",
            urn:ietf:params:scim:schemas:extension:test:ExternalTestDetail:2.0"
            ],
            "id": "7d0d8b63-ce15-36b3-b9c7-e8ca82e89b5c",
            "userName": "테스트유저",
            "emails": [
                {
                    "value": "test@naver.com"
                }
            ],
            "active": true,
            "meta": {
                "created": "",
                "location": "scim/v1/Users",
                "lastModified": "",
                "resourceType": "User"
            },
            "urn:ietf:params:scim:schemas:extension:test:ExternalTestDetail:2.0": {
                "externalTestField": false
            }
        }
    ]
}

 

패치

 

@Getter
@Setter
public class PatchTest {
    @JsonProperty("schemas")
    private List<String> schemas;
    @JsonProperty("Operations")
    private List<ScimOperations> operations;
}

Request Body

{
    "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
    "Operations": [{
        "op": "replace",
        "value": {
            "active": true
        }
    }]
}

Response Body

-유저 조회 결과와 동일

 

 

 

출처 

http://www.simplecloud.info/#Overview

http://www.simplecloud.info/specs/draft-scim-core-schema-01.html#defs

https://datatracker.ietf.org/doc/html/rfc7643#section-6

 

SAML

 

- 마크업 랭귀지

인증 정보 제공자(identity provider)와 서비스 제공자(service provider) 간의 인증 및 인가 데이터를 교환하기 위한 XML 기반의 개방형 표준 데이터 포맷이 SAML이다. SAML이 기술하는 가장 중요한 요구사항은 웹 브라우저 통합 인증(SSO)이다.

 

Why SAML ?

 

SAML은 확장되는 수많은 플랫폼, 디지털 접점 및 장치에서 사용자를 인증하고 권한을 부여하는 안전한 방법을 제공합니다.

 

SAML은 IdP(사용자 자격 증명을 보유하는)와 SP 간에 IdP 방화벽 내부에서 발생하는 토큰 기반 인증 교환을 활성화하기 때문에 여러 웹 응용 프로그램 암호에 대한 필요성을 느끼지 못합니다. 

 

SAML은 SSO(Single Sign-On) 기능을 활성화하여 주요 문제를 해결합니다. 즉, 사용자가 일정 기간 동안 단일 자격 증명 집합으로 여러 속성에 대해 등록 또는 로그인하고 권한을 부여할 수 있습니다. SAML은 또한 단일 로그아웃 기능을 활성화하여 사용자가 한 사이트에서 로그아웃할 때 해당 회사가 소유한 다른 모든 서비스 제공업체에서 자동으로 로그아웃되도록 합니다.

 

SAML  용어

  • Identity Provider(IDP) : 인증의 중앙 집중식 지점 - SSO내에서의 ID저장소 
  • Service Provider(SP) : 유저가 로그인을 시도하는 응용 프로그램
  • SAML Request : SP가 IDP에게 커뮤니케이션을 보내는 것
  • SAML Response : IDP가 SAML Request에 응답하는 것 
  • Assertion : SAML Response에 담은 ID제공자가 사용자 인증을 포함하는 서비스 제공자에게 보내는 XML문서
    • Assertion은 인증/속성/권한 부여 세 가지 유형이 있다. 
      • 인증 Assertion은 사용자 식별을 증명하고, 로그인 한 시간과 인증 방법을 제공한다. 
      • 속성 Assertion은 SAML 속성을 서비스 공급자에게 전달합니다. SAML 속성은 사용자에 대한 정보를 제공하는 특정 데이터 조각입니다. 
      • 권한 부여 결정 Assertion은 사용자가 서비스를 사용할 수 있는 권한이 있는지 또는 IDP가 암호 오류 또는 서비스에 대한 권한 부족으로 인해 요청을 거부했는지 여부를 나타냅니다. 
  • XML Signatures (DSig) : Assertion이 사용하는 XML 서명
  • Assertion Consumer Service : SP에서 Assertion을 받는 특정 EndPoint이며 XML Document를 검사한다. 
  • Attribute : SAML Response에는 유저에 대한 여러 정보들 
  • Relay State: SAML Response에서 매우 중요하게 알아야 되는 정보들

SAML 사용 예에서 주체는 서비스를 서비스 제공자로부터 요청한다. 이 서비스 제공자는 식별 어서션(assertion)을 인증 정보 제공자로부터 요청하여 가져온다. 이 어서션(assertion)에 기초하여, 서비스 제공자는 접근 제어 결정을 할 수 있다. 즉, 연결된 주체에 대해 일부 서비스를 수행할지의 여부를 결정할 수 있다.

 

 

위 용어를 토대로 SAML을 설명하자면

IdP(ID 공급자)가 SP(서비스 공급자)에 인증 자격 증명을 전달할 수 있도록 하는 open standard이다.
SAML을 통해 하나의 자격 증명 세트를 사용하여 다양한 웹 사이트에 로그인할 수 있게 하며
ID 공급자와 서비스 공급자 간에 사용자 인증 및 권한 부여를 전달하는 안전한 방법이다.

 

How it works?

  1. 사용자가 Google에서 호스팅하는 서비스 또는 애플리케이션에 연결을 시도합니다.
  2. 서비스(응용 프로그램) 파트너는 파트너의 SSO 서비스에 대한 URL에 인코딩 및 포함된 SAML 인증 요청을 생성합니다. 식별자로 설정된 매개변수는 수정이나 검사 없이 다시 전달됩니다.
  3. 애플리케이션은 파트너의 SSO 서비스에 제출할 인코딩된 SAML 인증 요청을 포함하는 리디렉션을 사용자의 브라우저로 보냅니다.ID 파트너는 SAML 요청을 디코딩하고 사용자를 인증합니다.
  4. ID 파트너는 인증된 사용자의 ID 및 속성이 포함된 SAML 어설션을 생성합니다.
  5. 인코딩된 SAML 응답은 브라우저로 다시 전달되고 브라우저는 응답을 ACS(액세스 제어 서버) URL로 보냅니다.
  6. SAML 2.0 사양에 따라 이 응답은 파트너의 공개 및 비공개 DSA/RSA 키로 디지털 서명됩니다.
  7. 사용자가 Google 호스팅 애플리케이션에 로그인되어 있습니다.
사용자가 SAML 지원 애플리케이션에 로그인하면 서비스 제공자가 적절한 ID 제공자에게 권한 부여를 요청합니다. ID 제공자는 사용자의 자격 증명을 인증한 다음 사용자에 대한 권한을 서비스 제공자에게 반환하고 사용자는 이제 애플리케이션을 사용할 수 있습니다.
 

+ 정확하게 구현하지 않으면 보안에 취약한 점이 있기 때문에 주의가 필요하다.

 

 

 

출처 

 

통합 인증 - 위키백과, 우리 모두의 백과사전

통합 인증(영어: Single Sign-On; SSO)은 한 번의 인증 과정으로 여러 컴퓨터 상의 자원을 이용 가능하게 하는 인증 기능이다. 싱글 사인온, 단일 계정 로그인, 단일 인증이라고 한다. 예를 들어 어느

ko.wikipedia.org

https://web.archive.org/web/20160304032626/http://www.gigya.com/blog/the-basics-of-saml/

 

The Basics of SAML • Gigya

Gigya is the leader in customer identity management. Read our post, The Basics of SAML.

web.archive.org

 

 

출처 : 책 자바 성능 튜닝이야기 -'왜 자꾸 String을 쓰지 말라는거야' 편

 

이 책에 나온 초보 개발자 나초보는 서비스를 개발하고 나서 보니 GC가 많이 발생된단 사실을 알게 되었고

성능을 올리기 위해 GC에 영향을 끼치고 있던 String 부분을 개선해보기로 하였다. 

 

문제를 일으키던 부분은

String a = "test"; / for문을 통해 a += "XXX";

이런식으로 String에다 계속 값을 더하는 부분이었다.

String을 이렇게 사용하면 성능 적인 부분에서 문제를 일으킬 수 있다.

 

for문이 100,1000번 이상 돌아간다 가정해보면 메모리 사용률이 올라가고, 응답속도는 낮아질 것이다. 

 

그렇다면 어떻게 해야 할까?

  • StringBuffer 클래스와 StringBuilder 클래스를 사용하여야 한다. 
    • append() 메서드를 활용

 

StringBuffer 클래스와 StringBuilder 클래스의 차이는 

StringBuffer 클래스는 스레드에 안전하게 설계되어 있으므로 여러 개의 스레드에서 하나의 StringBuffer객체를 처리해도 전혀 문제가 되지 않는다. 반면 StringBuilder 클래스는 단일 스레드에서의 안정성만을 보장한다. 

 

String a = new String();
StringBuffer b = new StringBuffer();
StringBuilder c = new StringBuilder();

for(int loop = 0 ; loop < 10000; loop++) {
	a += "abcde";
}

for(int loop = 0 ; loop < 10000; loop++) {
	b.append("abcde");
}
String tempB = b.toString();

for(int loop = 0 ; loop < 10000; loop++) {
	c.append("abcde");
}
String tempC = c.toString();

이런 소스가 실행된다면 결과가 어떻게 될까? 어느 것이 가장 빠르고 메모리를 적게 사용할까? 

 

  응답시간 생성된 임시 객체수 메모리 사용량
a (String) 95초 4,000,000 약 95Gb
tempB (StringBuffer) 0.24초 1400 약 37.5Mb
tempC (StringBuilder) 0.17초 1400 약 37.5Mb

그렇다, 응답시간과 메모리 사용량에서 엄청난 차이가 보인다

응답시간과 메모리 사용량에서 가장 좋은 성능을 보인건 StringBuilder이다. 

 

왜 이럴까?

새로이 더해진 문자열은 새로운 주소를 갖는 객체가 생성이 되기 때문이다. 

a에 "abcde"를 더하면 새로운 String클래스의 객체가 만들어지고, 이전에 있던 a객체는 필요 없는 쓰레기 값이 되어 GC대상이 된다. 이러한 작업이 반복 수행되면서 메모리를 많이 사용하게 되고, 응답 속도에도 많은 영향을 미치게 된다. GC를 하면 할수록 시스템의 CPU를 사용하게 되고 시간도 많이 소요된다. 그래서 프로그래밍을 할 때 메모리 사용을 최소화하는 것은 당연한 일이다. 

 

Wrap-up

  • String은 짧은 문자열을 더할 경우 사용한다.
  • StringBuffer는 스레드에 안전한 프로그램이 필요할 때나, 개발 중인 시스템의 부분이 스레드에 안전한지 모를 경우 사용하면 좋다. (클래스에 static으로 선언한 문자열을 변경하거나, singleton으로 선언된 클래스에 선언된 문자)
  • StringBuilder는 스레드에 안전한지의 여부와 전혀 관계 없는 프로그램을 개발할 때 사용하면 좋다. 메서드 내에 변수를 선언하는 경우가 이에 해당되겠다.
  • WAS나 시스템이 JDK5.0 이상을 사용한다면, 컴파일러에서 자동으로 StringBuilder로 변환해 주긴 한다. 하지만 반복 루프를 사용해서 문자열을 더할 때는 객체를 계속 추가한다는 사실에 변함이 없으므로 StringBuilder, StringBuffer사용을 권장한다. 

 

https://shlegeris.com/2016/08/14/algorithms

 

My advice on studying algorithms

Software engineering interviews often ask whiteboard algorithms questions. Here’s my advice on how to study for them. (My credentials on this topic are: I have passed a lot of whiteboard interviews, including at Google and Apple; as part of my job I prep

shlegeris.com

  •  Hash tables
  •  Linked lists
  •  Set 
  •  Map

필수 메소드의 구현 방식, 런타임에 동작 방식

  •  Breadth-first search, depth-first search
  •  Quicksort, merge sort
  •  Binary search
  •  2D arrays
  •  Dynamic arrays
  •  Binary search trees
  •  Dynamic programming
  •  Big-O analysis

 

etc

  •  HTTP (at the protocol level)
  •  Databases (indexes, query planning)
  •  CDNs
  •  Caching (LRU cache, memcached, redis)
  •  Load balancers
  •  Distributed worker systems

 

  • 그래프 알고리즘: 너비 우선 탐색(breadth first search), 깊이 우선 탐색(depth first search), 다익스트라 알고리즘 (dikstra’s algorithm)
  • 빠른 정렬 알고리즘 하나. 병합 정렬(mergesort) 또는 퀵 정렬(quicksort)
  • 배열에서 수행하는 이진 검색. 이 알고리즘은 제대로 작성하기 매우 까다롭고 대략적으로 알고리즘을 이해하고 있더라도 코드로 작성해볼 가치가 있습니다.

 

 

-

https://edykim.com/ko/post/advice-on-learning-algorithms/

+ Recent posts