기존 GitOps 운영 글 에서 Prometheus와 Loki로 상태를 보는 흐름을 다뤘습니다. 오늘 목표는 관측 서비스 접근 경계와 수집 데이터의 비밀 제외 를 함께 확인하는 것입니다. 앱을 보호하면서 로그 화면은 누구나 볼 수 있게 두면 경계가 남습니다. 읽기 화면에도 운영 정보가 있습니다 Prometheus API·metrics·디버그 경로에는 시스템 정보가 있습니다. 공개 노출을 피하고 필요한 접근 통제를 구성해야 합니다. 운영자만 써야 하는 관리·재로딩 경로도 따로 점검하세요. 대시보드의 보기 권한만 설정했다고 데이터 소스의 접근이 제한됐다고 단정하면 안 됩니다. Prometheus 보안 모델 전제는 실습 관측 namespace, 이미 검토된 인증 프록시와 TLS, 합성 telemetry 데이터입니다. 실제 토큰과 사용자 데이터를 테스트 입력으로 사용하지 않습니다. 그림의 각 경계는 독립적으로 확인합니다. Collector에서 하나의 속성을 지웠다고 앱 로그와 모든 backend 데이터가 정제되는 것은 아닙니다. Loki의 tenant 헤더는 로그인 비밀번호가 아닙니다 Loki의 multi-tenant 모드에서 X-Scope-OrgID 는 tenant 식별에 쓰입니다. 클라이언트가 임의로 헤더를 넣을 수 있는 경로를 그대로 신뢰하면 안 됩니다. 인증 프록시가 확인한 신원에서 tenant를 결정하고 전달 경로를 통제하는 설계가 필요합니다. auth_enabled: true 하나가 완성된 사용자 인증 시스템은 아닙니다. Loki 인증 안내 인증 프록시를 두어도 backend를 다른 주소로 직접 호출할 수 있다면 우회 경로가 남습니다. Kubernetes Service·Ingress·NetworkPolicy와 실제 route를 같이 점검하세요. Loki mTLS는 전송 계층 신원 검증이며 tenant 권한 매핑은 별도입니다. Collector 속성 삭제 예제 아래는 해당 processor가 포함된 Collector 배포판 의 설정 조각입니다. receiver·exporter·TLS와 인증 구성은 별도로 준비해야 합니다. 모든 Collector 배포판에 같은 component가 있다고 가정하지 마세요. processors: attributes/remove-sensitive: actions: - key: http.request.header.authorization action: delete - key: user.email action: delete - key: session.id action: delete service: pipelines: traces: receivers: [otlp] processors: [attributes/remove-sensitive, batch] exporters: [otlp/approved] processor를 정의하는 것과 pipeline에서 사용하는 것은 다릅니다. 예제는 trace pipeline에 연결했습니다. logs·metrics를 함께 받는다면 그 경로와 attribute 위치도 따로 검토해야 합니다. 가능하면 앱에서 처음부터 민감값을 수집하지 않는 것이 출발점입니다. OpenTelemetry 민감 데이터 처리 삭제할 key 이름은 사용한 instrumentation과 실제 수집 형태에 맞춰야 합니다. log body, resource attribute, URL query에 비밀이 있다면 위 세 속성 삭제로 해결되지 않습니다. 알려진 키를 지우는 예제를 전체 데이터 익명화라고 부르지 않았습니다. 합성 입력으로 확인하기 합성 attribute 예제 처리 목표 http.request.header.authorization 삭제 user.email 삭제 session.id 삭제 http.request.method 유지 로컬에서는 이 표대로 속성 집합이 바뀌는지만 검사했습니다. 실제 Collector에 합성 span을 보내 backend에 남은 값을 읽는 통합 검증은 별도입니다. 민감값이 들어 있는 원본을 테스트 로그로 출력하면 검증 과정에서 유출이 생길 수 있으므로 값 대신 제거 여부만 기록하세요. 다음은 독자용 설정 조회 안내입니다. 사용자 환경에는 실행하지 않았습니다. kubectl get service -n observability kubectl get ingress -n observability kubectl get networkpolicy -n observability 그다음 승인된 실습에서 인증 없는 조회가 거부되는지, 허용 사용자가 자기 tenant만 읽는지, 다른 tenant 헤더를 시도해도 범위가 바뀌지 않는지 검사합니다. 존재하지 않는 경로의 404와 인증 거부를 구분해야 합니다. 적용과 복구 합성 데이터부터 시작해 좁은 pipeline에 정제를 적용하고 필요한 운영 정보가 남는지 확인합니다. 대시보드 장애가 생기면 익명 접근을 여는 대신 인증 전달·권한·TLS 신뢰와 프록시 우회 경로를 확인합니다. 되돌림은 검토된 이전 Collector 구성에서 필요한 측정값을 복원하는 작업입니다. 비밀 수집을 다시 켜는 방식으로 화면을 복구하지 않습니다. 이미 저장된 민감 데이터는 새 processor로 소급 삭제되지 않으므로 별도 보존·삭제 절차가 필요합니다. 확인 문제 auth_enabled: true 만으로 Loki 사용자 로그인까지 완성될까요? processor를 정의만 해도 모든 telemetry가 지나갈까요? 세 attribute를 삭제하면 log body의 비밀도 없어질까요? 답과 해설: 1. 신원 인증과 tenant 매핑은 별도입니다. 2. 각 pipeline에 연결해야 합니다. 3. body와 다른 위치는 따로 점검해야 합니다. 오늘은 수집 위치를 나누고, 내일은 다른 tenant 반례를 설명해 보세요. 일주일 뒤에는 공개 route와 telemetry 필드 목록을 다시 검토하세요. 버전과 검증 범위 2026-10-04 Prometheus·Loki latest 및 OpenTelemetry 공식 문서 확인. 설치 버전·Collector 배포판 지원은 실환경에서 확인해야 합니다. 로컬 YAML, processor 연결, 합성 attribute 제거·pipeline 누락 반례를 검증했습니다. 인증 프록시·Collector·backend 통합 동작은 실행하지 않았습니다.
기존 CNCF 시리즈 에서 Harbor의 이미지 저장소 역할을 살펴봤습니다. 이번 목표는 누가 올리는지, 배포할 내용이 무엇인지, 어떤 검사를 거쳤는지 를 분리해서 확인하는 것입니다. 저장소 로그인 성공만으로 이미지가 믿을 만해지지는 않습니다. 같은 이름으로 다른 내용이 들어오면 가상의 app:release 를 배포했다고 해 보겠습니다. 태그가 나중에 다른 이미지로 이동하면 같은 YAML을 재배포해도 내용이 달라질 수 있습니다. Harbor의 tag immutability는 선택한 태그 변경을 제한합니다. 배포 시 digest로 대상을 지정하면 내용 식별을 더 명확하게 기록할 수 있습니다. Tag immutability 전제는 Harbor 2.14 문서 기준의 프로젝트, TLS 신뢰 경로, 승인된 robot 계정, 실제 이미지와 스캔 도구입니다. 배포 주체와 이미지 업로드 주체를 분리하는 상황을 다룹니다. 각 단계는 서로 다른 질문입니다. 스캔이 끝났다는 사실과 신뢰한 빌드 주체의 서명이 확인됐다는 사실도 구분해야 합니다. robot 계정은 역할별로 프로젝트 robot은 해당 프로젝트의 자동 작업에 사용합니다. 배포용 계정에는 Pull만, 이미지 업로드 계정에는 필요한 Pull과 Push를 검토합니다. Harbor 2.14에서는 Push를 부여할 때 Pull도 함께 필요합니다. 만료·교체·비활성화 경로를 미리 정해 두세요. 프로젝트 robot 권한 역할 예시 권한 제외할 권한 배포 이미지 읽기 Pull Push·삭제·관리 CI 업로드 Pull + Push 프로젝트 관리 검토 담당 필요한 결과 조회 장기 robot 비밀 공유 robot 비밀은 secret store나 승인된 런타임 전달 경로로 다룹니다. 명령 인수·워크플로 로그·글 예제에 실제 값을 넣지 않습니다. 토큰을 만들었다는 기록과 배포가 어떤 토큰을 사용하는지는 별도로 점검해야 합니다. digest를 배포 정의에 남기기 다음은 Deployment의 spec.template.spec 에 들어가는 PodSpec 조각 입니다. registry와 digest는 합성이므로 그대로 pull할 수 없습니다. 실제 승인된 이미지의 digest와 이미 준비한 pull Secret 이름으로 교체해야 합니다. automountServiceAccountToken: false imagePullSecrets: - name: study-registry-pull containers: - name: app image: registry.example.com/study/app@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef imagePullPolicy: IfNotPresent digest는 내용 식별입니다. 그 자체가 출처 신뢰나 취약점 없음의 증명은 아닙니다. IfNotPresent 는 로컬 캐시 사용을 허용하므로 registry에서 pull을 차단했어도 이미 캐시된 이미지나 실행 중인 워크로드를 자동으로 제거하지 않습니다. 실제 배포 경계는 별도 검토해야 합니다. 스캔과 서명 결과를 읽는 기준 Not Scanned , Unsupported , Scanning , 실패와 Complete 를 구분합니다. 스캐너가 지원하지 않는 대상은 취약점 0개와 같지 않습니다. 스캐너·DB 시점·대상 아키텍처·적용 임계값을 함께 기록하세요. Harbor 스캔 상태 Harbor는 Cosign·Notation 서명을 저장하고 content trust 기능을 제공하지만, 화면에 서명 accessory가 보이는 사실만으로 조직의 신뢰한 signer를 검증한 것은 아닙니다. 배포 전에 어떤 신원을 신뢰하는지 명시한 검증 정책이 필요합니다. 서명과 content trust 조회와 변경 검증 아래는 독자용 조회 안내입니다. 사용자 registry·클러스터에는 실행하지 않았습니다. kubectl get deployment app -n image-study -o jsonpath='{.spec.template.spec.containers[*].image}' kubectl get pods -n image-study -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.status.containerStatuses[*].imageID}{"\n"}{end}' 템플릿과 실행된 imageID를 비교하고, Harbor UI에서 해당 digest의 스캔 상태·robot 권한·immutable 규칙을 조회합니다. tag와 digest의 관계, 다중 아키텍처 image index와 실제 플랫폼 이미지 차이도 남겨야 합니다. 실습에서 제한된 태그 재업로드가 거부되는지, pull 전용 계정의 Push가 거부되는지 확인합니다. 문제 발생 시 임계값을 무조건 낮추거나 TLS 검증을 끄지 않습니다. 되돌림은 이전에 검증한 digest와 배포 정의를 복원하는 것입니다. 그 digest의 현재 취약점 상태도 다시 검토하세요. 확인 문제 digest가 고정되면 취약점과 출처 검증도 끝난 것일까요? Unsupported 는 취약점이 없다는 결과일까요? registry pull 차단이 실행 중인 Pod까지 제거할까요? 답과 해설: 1. 내용 식별과 보안 검증은 별도입니다. 2. 검사하지 못한 상태입니다. 3. 실행 중이거나 캐시된 이미지는 별도 경계입니다. 오늘은 세 질문을 배포 기록에 넣고, 내일은 태그 이동 반례를 설명해 보세요. 일주일 뒤에는 robot 만료와 스캔 시점을 점검해 보세요. 버전과 검증 범위 2026-10-04 Harbor 2.14.0 문서 확인. 로컬 YAML과 digest 형식, tag-only 반례, Pull/Push 권한 분리·스캔 상태 분류를 검증했습니다. 실제 robot 인증·이미지 스캔·서명 검증·pull·배포는 실행하지 않았습니다.
S3에 저장된 파일이 암호화됐다는 표시를 보고 외부 공개도 막혔다고 생각하기 쉽습니다. 하지만 정상 권한으로 파일을 읽는 요청에는 서비스가 내용을 제공할 수 있습니다. 이번에는 공개 접근, 객체 소유권, 전송 보호 를 각각 점검하겠습니다. 기존 AWS 시리즈 에서 서비스별 역할을 정리한 데 이어, 이번에는 정상 업무를 유지하면서 접근 범위를 줄이는 방법을 살펴봅니다. S3 버킷과 객체, IAM 정책을 알고 있으면 읽을 수 있습니다. 사내 보고서를 저장하는 가상 버킷이며 공개 웹사이트 용도는 아닙니다. 서로 다른 세 가지 질문 Block Public Access는 정책과 ACL 등을 통해 공개 접근이 허용되는 것을 제한합니다. 버킷 설정만 보지 않고 계정과 적용되는 조직 설정, 액세스 포인트도 함께 확인해야 합니다. 더 엄격한 조합이 적용될 수 있습니다. S3 공개 접근 차단 Object Ownership의 BucketOwnerEnforced 는 ACL을 비활성화하고 버킷 소유자가 객체를 소유하도록 하는 설정입니다. IAM과 버킷 정책이 필요 없어지는 기능이 아닙니다. 기존 업로드 클라이언트가 ACL을 보내는지 전환 전에 확인합니다. 객체 소유권과 ACL 전송 보호는 HTTPS를 사용하는 질문입니다. 저장 암호화 여부와 다른 경계입니다. 데이터가 저장될 때 보호돼도 네트워크 요청 자체를 HTTP로 허용해 둘 수 있습니다. 그림의 세 칸은 어느 하나만 통과하면 충분하다는 뜻이 아닙니다. 정상 역할이 필요한 파일만 읽는지까지 별도 확인합니다. 버킷 속성의 예 아래 JSON은 CloudFormation AWS::S3::Bucket 의 Properties 에 들어가는 속성 조각 입니다. 버킷 정책과 암호화 설정, 전체 템플릿은 포함하지 않았습니다. { "PublicAccessBlockConfiguration": { "BlockPublicAcls": true, "IgnorePublicAcls": true, "BlockPublicPolicy": true, "RestrictPublicBuckets": true }, "OwnershipControls": { "Rules": [{"ObjectOwnership": "BucketOwnerEnforced"}] } } 네 항목을 모두 참으로 적었습니다. 각각 같은 설정의 별명이 아니므로 하나만 켜고 같은 효과라고 생각하지 않습니다. 기존 ACL과 정책 내용이 정리됐다는 의미도 아닙니다. 구조와 용도는 PublicAccessBlockConfiguration , OwnershipControls 에서 확인할 수 있습니다. HTTPS 요구는 별도 정책입니다 아래는 가상 버킷 정책의 거부 Statement입니다. 권한을 부여하는 전체 정책은 아닙니다. AWS 서비스 간 호출에서는 요청 컨텍스트가 일부 가려질 수 있어 서비스 주체를 구분하는 조건도 넣었습니다. { "Effect": "Deny", "Principal": "*", "Action": "s3:*", "Resource": [ "arn:aws:s3:::amzn-s3-demo-hardening", "arn:aws:s3:::amzn-s3-demo-hardening/*" ], "Condition": {"Bool": { "aws:SecureTransport": "false", "aws:PrincipalIsAWSService": "false" }} } Principal: "*" 가 있지만 이 Statement는 Deny 입니다. 별표만 보고 공개 허용 정책이라고 판단하면 의미가 바뀝니다. 예제는 두 조건이 함께 맞는 비서비스 주체의 HTTP 요청을 거부하려는 것입니다. HTTPS 요청을 허용하는 권한은 별도로 있어야 합니다. S3 전송 암호화 권장 사항 , AWS 서비스 주체 조건 기존 서비스가 끊기지 않도록 버킷 정책, 액세스 포인트, 업로드 ACL, 공개 배포 여부를 목록으로 만듭니다. 테스트 버킷에서 정상 역할의 업로드·읽기가 되는지 확인합니다. 권한 없는 익명 읽기와 HTTP 요청은 서로 다른 시험으로 확인합니다. 공개 웹사이트 같은 예외 용도는 이 사내 보고서 예제와 분리해 설계합니다. 되돌릴 때는 실패한 클라이언트의 호출 조건을 먼저 확인하고 바꾼 항목만 복구합니다. 문제를 해결하려고 계정 전체의 공개 접근 차단을 무작정 끄면 다른 버킷까지 영향을 받을 수 있습니다. 기존 공개 접근이 필요한지는 소유자와 검토하고, 예외의 범위를 기록합니다. 미리 서명된 URL도 따로 생각해야 합니다. URL을 발급한 주체의 권한과 만료가 관련되며, URL을 공유하면 의도한 상대 외에도 사용될 수 있습니다. “공개 차단을 켰으니 URL 공유도 신경 쓰지 않아도 된다”는 결론으로 이어지지 않습니다. 로컬 검증: 두 JSON 조각을 파싱하고 공개 차단 네 항목, ACL 비활성화, TLS 거부 조건을 검사했습니다. 공개 차단 하나를 끈 반례와 Deny 를 Allow 로 바꾼 반례는 탈락했습니다. 실제 S3 접근 평가, 업로드 호환성, HTTPS 연결은 시험하지 않았습니다. 확인 문제 저장 암호화가 켜져 있으면 익명 읽기도 차단될까요? Deny 의 Principal: "*" 는 모두에게 권한을 주는 뜻일까요? 정상 업로드가 실패할 때 공개 차단 전체를 끄기 전에 무엇을 볼까요? 답과 해설 아닙니다. 저장 보호와 읽기 권한은 다릅니다. 아닙니다. 조건에 맞는 요청을 거부하는 범위를 나타냅니다. 업로드 ACL, 소유권 전환, 요청 프로토콜과 적용된 정책을 봅니다. 복습 오늘은 공개 차단·소유권·TLS가 답하는 질문을 하나씩 써 보세요. 내일은 HTTPS이지만 권한 없는 요청이 왜 여전히 거부돼야 하는지 설명해 보세요. 일주일 뒤에는 KMS 복호화 권한까지 포함해 읽기 경로를 그려 보세요. 확인일: 2026-10-04, 한국 시간 . S3와 CloudFormation 속성, IAM 전역 조건 키 기준입니다. 모든 버킷 이름은 가상입니다.
Reliable swimming pool maintenance in Abu Dhabi protects your water quality, your equipment, and your family's health. Atlanta Pools sees every day how heat, dust, and humidity push pools to their limits. However, a clear routine keeps most problems away. In this guide, you will learn which tasks matter, how often to perform them, and when to call experts. Moreover, you will see how pool care connects with surfaces, leaks, lighting, gardens, and water features. Want crystal-clear water all year? Book a free inspection and let our team check your pool today. Why Swimming Pool Maintenance in Abu Dhabi Matters More Than Elsewhere Abu Dhabi pools face harsh conditions. Summer air passes 45°C, and water often stays above 30°C. Warm water speeds up algae and bacteria growth. As a result, a neglected pool can turn green within days. Strong sunlight also burns off chlorine, so protection fades quickly. Dust adds more pressure. Wind carries sand into the water, and filters clog faster. Meanwhile, salt air near the coast attacks metal fittings and stone. For these reasons, a smart swimming pool investment always includes a long-term care plan. Villa owners feel the difference most. A modern villa with pool ideas guide shows how pools shape daily life, from morning swims to evening gatherings. Therefore, clean water becomes part of the home experience, not just a technical detail. Rules also matter. Authorities expect pools to stay hygienic and safe. The municipality pool hygiene guidance highlights regular upkeep and proper water quality. Consistent swimming pool maintenance in Abu Dhabi helps owners meet these expectations with confidence. Time also works against owners. Algae can take hold in a single weekend, and fixing a green pool costs far more than preventing one. Therefore, steady swimming pool maintenance in Abu Dhabi saves chemicals, energy, and stress. Owners who skip routine care often face drained pools, replaced filters, and weeks without swimming. Children and older family members also need extra protection. Their skin and eyes react more strongly to poor water quality, so stable chemistry is a health matter. What Swimming Pool Maintenance in Abu Dhabi Includes Maintenance covers the whole pool system, not only the water you see. Technicians test, adjust, inspect, and repair every key part. The list below shows the core tasks: Water testing: Technicians measure chlorine, pH, alkalinity, calcium hardness, and stabiliser. Chemical balancing: They add only what the readings justify. Skimming and brushing: They remove debris and stop biofilm from forming. Vacuuming: They lift fine silt from the pool floor. Basket and strainer care: They keep water flowing freely. Filter service: They backwash sand filters or rinse cartridges. Equipment checks: They inspect pumps, valves, heaters, and controls. Cleaning and maintenance work together. Professional pool cleaning services handle the visible surface, while maintenance protects the systems behind it. Many owners also read our guide to a reliable swimming pool cleaner to understand what a good visit looks like. Records complete the picture. After each visit, technicians log readings and repairs. This history reveals trends, such as slowly rising pressure or falling chlorine. Therefore, strong swimming pool maintenance in Abu Dhabi always includes written reports. Technicians also follow a clear order of work. First, they test the water. Next, they clean the surface and floor. Then they adjust the chemistry once circulation has mixed the water. This sequence matters, because adding chemicals before cleaning wastes product. Skilled teams delivering swimming pool maintenance in Abu Dhabi follow it on every visit. Pumps, Filters, Lighting, and Circulation Circulation keeps water clean. The pump pulls water through the skimmers, pushes it through the filter, and returns it to the pool. If this loop fails, chemistry alone cannot save the water. Therefore, regular equipment checks deserve equal attention. Pumps work hard in Abu Dhabi. Long run times and high heat wear out seals and motors. Warning signs include noise, vibration, and weak flow. When a unit fails, swimming pool pump installation by trained technicians restores proper circulation and lowers energy use. Pool design also changes the routine. An overflow swimming pool design uses balance tanks, weirs, and extra pipework that need regular flushing. Likewise, saltwater systems need cell inspections and salinity checks. Lighting needs care too. Moisture can enter damaged seals and shorten the life of fittings. Our swimming pool lights guide explains the main types and safety points. Technicians should test lights during routine visits and report flickering or discolouration. Filters deserve a closer look. Sand filters need regular backwashing, while cartridges need rinsing and eventual replacement. A rising pressure gauge usually signals a clogged filter. Meanwhile, a falling gauge may point to a pump or valve problem. Professional swimming pool maintenance in Abu Dhabi includes reading these signals and acting early. Calibration also matters for dosing systems. Sensors drift over time, so technicians check them regularly. Accurate readings always mean accurate chemical decisions. Tiles, Coping, and Surfaces Surfaces take constant punishment. Sun, chemicals, and swimmers all wear them down. Tiles lose grout, coping stones fade, and plaster roughens. Rough surfaces then trap dirt and feed algae. Tiles deserve regular attention. Sunscreen and minerals leave a ring at the waterline that needs scrubbing. Choosing durable finishes also helps, so explore the best swimming pool tiles for Abu Dhabi homes before you replace damaged areas. The pool edge matters as well. Heat-resistant swimming pool coping tiles stay cooler underfoot and protect the wall from water damage. Meanwhile, loose or cracked coping lets water seep behind the shell. Inspect the edge every few months and repair gaps quickly. Clean surfaces also protect water balance. Smooth tiles shed algae more easily than rough plaster. As a result, careful surface care lowers chemical use and reduces brushing time. Maintenance needs differ by finish. Tiles clean easily with regular brushing, while plaster needs careful chemistry to avoid staining. Grout also needs inspection, because gaps let water reach the shell. Ask your technician for a simple care guide, so you protect surfaces from the first week. Consistent swimming pool maintenance in Abu Dhabi keeps finishes attractive far longer. Waterline care deserves a reminder. Sunscreen, body oils, and minerals leave a dull ring that needs regular scrubbing and the right cleaner. Leaks, Waterproofing, and Early Repairs Small leaks cause big losses. A pool that drops more than a few centimetres a week may be leaking. Meanwhile, hidden leaks damage soil, paving, and nearby structures. Therefore, act quickly when the water level falls without clear reason. Start with a simple bucket test to compare pool and bucket evaporation. Then call specialists if the gap looks large. A professional pool leak detection service can trace pipe, skimmer, and shell leaks without breaking the deck. Waterproofing also protects the structure. Failed membranes allow water to reach concrete and reinforcement. Read our swimming pool waterproofing guide to learn how materials and methods differ. Some pools need more than repairs. Cracked plaster, stained tiles, and worn finishes may call for a swimming pool renovation company to resurface the shell. Fresh finishes improve water clarity and cut cleaning time. Early action keeps swimming pool maintenance in Abu Dhabi simple and affordable. Leaks often start small. A worn seal, a loose fitting, or a cracked pipe can waste thousands of litres over a season. Moreover, constant water loss dilutes chemicals and raises bills. Technicians who perform swimming pool maintenance in Abu Dhabi watch the water level every visit, so they spot unusual loss early. Seasonal Schedules for Villas, Indoor Pools, and Private Retreats Pool type and season decide how often technicians should visit. A simple calendar keeps your plan realistic. Use the guide below as a starting point. Summer (June to September): Villa pools usually need two to three visits each week. Test chlorine and stabiliser often, because heat burns sanitiser fast. Autumn (October to November): Clear fallen leaves, scrub the waterline, and inspect equipment after the long summer. Winter (December to February): Cooler water uses less chlorine. Therefore, one or two visits a week often suffice, but equipment checks still matter. Spring (March to May): Descale tiles, service filters, and prepare the system for rising heat. Different pools need different care. A private pool Abu Dhabi setup for a hotel room or spa sees heavy use and needs close monitoring. Likewise, an indoor pool Abu Dhabi needs extra attention to humidity, ventilation, and air quality. Dust storms break every schedule. After heavy dust, book an extra visit within a day. This quick response keeps filters clear and protects pump motors. Reliable swimming pool maintenance in Abu Dhabi adapts to weather, not only to the calendar. Holidays need a plan too. Many residents travel in summer, and an unattended pool can turn green within a week. Therefore, arrange extra visits before you leave and after you return. A written holiday plan makes swimming pool maintenance in Abu Dhabi easy, even when you are far away. Rooftop and plunge pools need special care as well. Small volumes change quickly, so testing must be frequent and doses must be precise. Contracts, AMC Plans, and Long-Term Costs Many owners prefer a yearly agreement. An annual maintenance contract bundles visits, testing, and priority support into one plan. As a result, costs become predictable, and help arrives faster during heatwaves. Compare pool AMC service contracts to see how scope and pricing differ. Check these points befor
Unity 2D 모바일 게임 FindClover 개발 중간점검 클로버를 찾아 제한 시간 안에 최대한 높은 점수를 획득하는 2D 모바일 게임 Unity / Android / Touch Input / JSON Save / 광고 / 성장 시스템 / 어빌리티 시스템 현재 제작하고 있는 FindClover 의 개발 과정을 중간점검해보려고 한다. 처음에는 단순히 화면에서 클로버를 찾아 터치하는 게임으로 시작했지만, 개발을 진행하면서 게임의 기본 루프뿐만 아니라 재화, 성장, 광고, 능력, 상점, 뽑기 시스템까지 점점 확장되었다. 이번 글에서는 지금까지 어떤 시스템을 구현했고, 개발 과정에서 어떤 문제를 해결했는지 정리한다. 1. FindClover는 어떤 게임인가? FindClover는 모바일 환경을 기준으로 제작하고 있는 2D 캐주얼 게임이다. 기본적인 게임 플레이는 간단하다. 게임 시작 화면에 여러 클로버가 생성된다. 제한 시간 안에 클로버를 찾아 터치한다. 세잎클로버와 네잎클로버를 구분하여 획득한다. 제한 시간이 종료되면 결과를 계산한다. 획득한 보상을 이용해 성장한다. 성장한 능력을 이용해 다시 게임을 플레이한다. 즉, 클로버 찾기 → 보상 획득 → 성장 → 다시 클로버 찾기 라는 반복 구조를 목표로 했다. 처음에는 게임의 핵심 플레이만 구현하는 것이 목적이었지만, 이후 반복 플레이에 대한 동기를 만들기 위해 성장 시스템과 재화 시스템을 추가했다. 2. 프로젝트 초기 구성 프로젝트 초기에 먼저 게임의 기본적인 구조를 만들었다. 초기 커밋에서는 다음과 같은 시스템을 순서대로 구현했다. Title / Option UI UI Manager Game Manager Clover Manager Clover Spawn Manager Touch / Drag 시스템 카메라 이동 Sound Manager Haptic Manager InGame UI Pause UI Game End UI Scene Load Manager 처음부터 모든 시스템을 완성하기보다는 게임의 기본적인 실행 흐름을 먼저 만드는 방향으로 진행했다. 특히 게임의 중심이 되는 부분은 GameManager → SpawnManager → CloverManager → TouchController 의 흐름이다. 3. 클로버 생성 시스템 게임의 핵심 오브젝트는 클로버이다. 클로버의 종류를 구분하고 이를 관리하기 위해 Clover 와 CloverManager 를 분리했다. Clover └─ 개별 클로버의 상태 및 동작 CloverManager └─ 클로버 전체 관리 SpawnManager └─ 게임 시작 시 클로버 생성 세잎클로버와 네잎클로버를 각각 관리하고, 스테이지 데이터에 따라 생성 개수와 크기를 다르게 설정할 수 있도록 구성했다. 이를 통해 스테이지마다 세잎클로버 개수 네잎클로버 개수 클로버 크기 제한 시간 보상 등을 다르게 설정할 수 있는 기반을 만들었다. 4. 모바일 터치 입력 구현 FindClover는 PC 게임이 아니라 모바일 게임을 목표로 했기 때문에 터치 입력이 매우 중요했다. 초기에는 단순 터치뿐만 아니라 화면을 드래그하여 맵을 확인하는 방식도 구현했다. Touch ├─ 클로버 선택 └─ Drag └─ 화면 이동 이 과정에서 Unity Input System을 이용해 터치 입력을 처리했다. 이후 실제 모바일 환경을 고려하면서 터치 UX를 계속 수정했다. 특히 중요한 문제가 화면 좌표와 월드 좌표의 차이 였다. 5. UI 좌표계와 월드 좌표계 문제 개발 중 클로버가 생성되는 영역을 조정하면서 좌표계를 크게 수정했다. 초기에는 월드 좌표를 기준으로 클로버의 생성 범위를 설정했다. X : -5.5 ~ 5.5 Y : -7.65 ~ 7.35 하지만 실제 모바일 UI를 기준으로 게임 화면을 구성하면서 UI 좌표를 기준으로 관리하는 것이 더 적합하다고 판단했다. 그래서 이후에는 Canvas 기준으로 다음과 같은 범위를 사용하도록 변경했다. X : -290 ~ 290 Y : -500 ~ 500 이 과정에서 단순히 좌표 값만 변경하는 것이 아니라, 터치 위치 → UI 좌표 → 게임 오브젝트 위치 의 관계를 다시 정리했다. 모바일 게임에서는 화면 해상도와 Canvas 설정에 따라 입력 좌표가 달라질 수 있기 때문에 이 부분이 생각보다 중요했다. 6. 클로버 찾기 판정 방식 개선 클로버를 찾는 과정에서도 UX 문제가 있었다. 처음에는 작은 영역을 기준으로 터치를 판정했지만, 모바일에서는 손가락으로 정확한 위치를 누르기 어려웠다. 그래서 일정 범위 안을 터치해도 클로버를 선택할 수 있도록 판정 영역을 조정했다. 초기에는 월드 좌표 기준으로 약 0.8 정도의 탐지 반경을 사용했고, 이후 UI 기반 구조에서는 약 80px 수준의 재선택 영역을 사용하도록 변경했다. 결국 중요한 것은 실제 스프라이트의 크기보다 사용자가 편하게 누를 수 있는 영역을 제공하는 것 이었다. 모바일에서는 정확한 판정보다 적절한 입력 관용성이 더 중요하다는 것을 확인할 수 있었다. 7. Depth Sorting 2D 게임이지만 클로버가 화면에 여러 개 겹쳐 보일 수 있기 때문에 깊이 표현도 필요했다. 이를 위해 Y값에 따라 Sort Order 를 변경하는 시스템을 구현했다. Y 위치 ↓ Depth 계산 ↓ Sorting Order 변경 이를 통해 화면에서 위쪽에 있는 오브젝트와 아래쪽에 있는 오브젝트가 자연스럽게 겹쳐 보이도록 만들었다. 현재는 BaseDepthSorter DynamicDepthSorter StaticDepthSorter 등으로 역할을 나누어 관리하고 있다. 8. GameManager와 게임 상태 게임 전체의 흐름은 GameManager 에서 관리한다. 현재 게임 상태는 크게 다음과 같이 구분했다. public enum GameState { Ready, Playing, GameOver } 게임이 시작되면 Playing 상태가 되고 제한 시간이 감소한다. 제한 시간이 0이 되면 게임을 종료하고 결과를 계산한다. 또한 스테이지 데이터와 현재 스테이지 인덱스를 연결하여 스테이지별 게임 설정을 사용할 수 있도록 했다. 이 구조를 통해 게임 플레이와 UI를 어느 정도 분리할 수 있었다. 9. 스테이지와 성장 시스템 게임의 반복 플레이를 만들기 위해 단순히 클로버를 찾는 것에서 끝내지 않고 성장 시스템을 추가했다. 현재 프로젝트에는 GrowthData 와 GrowthManager 를 중심으로 성장 시스템이 구성되어 있다. 성장을 통해 게임에서 얻을 수 있는 보상이나 플레이 효율을 높일 수 있도록 설계했다. 예를 들어 골드 획득량 증가와 같은 효과를 게임 플레이 결과에 적용할 수 있도록 했다. 게임 플레이 ↓ 스테이지 결과 ↓ 보상 계산 ↓ 성장 효과 적용 ↓ 최종 보상 이 구조를 만들면서 단순히 값을 증가시키는 것보다 보상 계산 과정에서 성장 효과를 연결하는 방식 을 고민하게 되었다. 10. 재화 시스템 게임 내 재화도 각각 별도의 Manager로 분리했다. 현재 주요 재화 시스템은 다음과 같다. Gold Gem Star HourGlass 각 재화는 별도의 Manager를 가지고 있으며 JSON을 이용해 저장한다. 예를 들어 Gold는 다음과 같은 데이터를 저장한다. [Serializable] public class GoldSaveData { public int totalGold; public string lastDailyRewardDate; public string lastAdResetDate; public int basicGoldAdCount; } 게임을 종료했다가 다시 실행해도 플레이어의 재화가 유지될 수 있도록 했다. 11. PlayerPrefs 대신 JSON 저장을 사용한 이유 FindClover에서는 주요 게임 데이터를 PlayerPrefs 보다는 JSON으로 저장하는 방향을 선택했다. 예를 들어 골드는 gold.json 능력 데이터는 ability.json 과 같은 방식으로 저장한다. JSON 저장을 사용하면 데이터 구조를 직접 정의할 수 있다는 장점이 있다. 특히 어빌리티 시스템처럼 Ability ID Count Upgrade Level 등 여러 데이터를 함께 저장해야 하는 경우 JSON 구조가 더 적합하다고 판단했다. 12. HourGlass 시스템 게임의 플레이 횟수 또는 플레이 자원 역할을 하는 HourGlass 시스템도 구현했다. 현재 기본 설정은 최대 보유량 : 5 회복 시간 : 8분 이다. 시간이 지나면 자동으로 회복되며, 게임을 실행하지 않은 동안에도 시간이 흐른 만큼 회복량을 계산한다. 마지막 회복 시간 ↓ 현재 시간과 비교 ↓ 경과 시간 계산 ↓ 회복 횟수 계산 ↓ HourGlass 증가 또한 광고 보상으로 HourGlass를 획득할 수 있고, 일정 시간 동안 무제한으로 사용할 수 있는 기능도 고려하여 구현했다. 13. 광고 시스템 모바일 게임이기 때문에 보상형 광고 시스템도 구현했다. Unity LevelPlay를 이용하여 광고 시스템을 구성했고, AdsManager 에서 광고 종류를 관리한다. 현재 코드에서는 다음과 같은 보상 종류를 관리하고 있다. FindClover EliminateObjects TimeExtend Revive GemAndGold BasicAbility RareAbility Gold Gem HourGlass 광고를 하나의 Manager에서 관리하고 광고 종류를 enum으로 구분하도록 구성했다. public enum AdRewardType { FindClover, EliminateObjects, TimeExtend, Revive, GemAndGold, BasicAbility, RareAbility, Gold, Gem, HourGlass } 개발 과정에서는 에디터에서 실제 광고를 기다리지 않고 테스트할 수 있도록 Mock Reward 방식도 사용했다. #if UNITY_EDITOR StartCoroutine(EditorMockReward(onRewarded)); return; #endif 덕분에 Unity Editor에서 광고 시청 과정을 빠르게 테스트할 수 있었다. 하지만 현재 완벽히 구현되진 않았다. 아직 테스팅 중이다. 14. 무료 보상과 일일 광고 제한 광고 시스템을 단순히 광고를 보여주는 기능으로 끝내지 않고 일일 제한과 무료 보상 시스템까지 연결했다. 예를 들어 골드의 경우 무료 일일 보상 ↓ 무료 보상 소진 ↓ 광고 보상 ↓ 일일 광고 제한 의 형태로 구성했다. 이 과정에서 날짜를 저장하고 다음 날이 되면 광고 횟수를 초기화하도록 구현했다. HourGlass와 Ability 시스템에도 비슷한 방식의 일일 광고 제한 구조를 적용했다. 15. Ability 시스템 현재 FindClover에서 가장 크게 확장하고 있는 부분이 Ability 시스템 이다. 초기 게임은 단순히 클로버를 찾는 구조였지만, 플레이를 반복할 이유를 만들기 위해 능력 시스템을 추가했다. 현재 AbilityManager 에서는 다음과 같은 데이터를 관리한다. Ability ID Ability Count Upgrade Level Ability Slot 그리고 플레이어의 어빌리티 데이터를 JSON으로 저장한다. 16. Ability 강화 구조 어빌리티는 동일한 능력을 여러 번 획득하여 강화하는 방식이다. 예를 들어 하나의 Ability가 여러 개 중복 획득되면 Count가 증가하고, 일정 개수 이상 모이면 Upgrade Level을 올릴 수 있다. 구조는 대략 다음과 같다. Ability 획득 ↓ Count 증가 ↓ 필요한 개수 충족 ↓ Upgrade ↓ Ability 효과 강화 최대 강화 레벨도 설정하여 무한히 성장하지 않도록 했다. 또한 Ability 효과는 Gold 획득량 증가와 같은 실제 게임 시스템과 연결했다. 17. Ability Box / Gacha 시스템 최근에는 Ability를 획득하는 방식으로 상자와 뽑기 시스템을 제작하고 있었다. 현재 구조에는 Basic Rare Epic Legendary 등의 등급이 존재한다. 확률표는 DrawProbabilityTable 이라는 ScriptableObject로 분리했다. [CreateAssetMenu(menuName = "Gacha/Draw Probability Table")] public class DrawProbabilityTable : ScriptableObject { public List<DrawLevelProbability> levels; } 이렇게 하면 코드에 확률을 직접 작성하는 대신 Unity Inspector에서 확률 데이터를 관리할 수 있다. 18. 뽑기 확률과 성장 단순한 고정 확률이 아니라 뽑기 레벨과 경험치를 함께 관리하도록 구현했다. 현재 AbilityManager에는 Rare Draw Level Legendary Draw Level Rare Draw EXP Legendary Draw EXP Rare Guarantee Legendary Guarantee 등의 데이터가 존재한다. 또한 일정 횟수마다 특정 등급 이상을 보장하는 천장 시스템도 구현하고 있다. 이를 통해 장기적으로 플레이할수록 뽑기 시스템 자체가 성장하도록 설계했다. 19. Ability Shop 제작 현재 개발의 마지막 단계에서는 Ability Shop을 제작하고 있다. ShopUI에서 구매 버튼을 누르면 구매 확인 팝업을 띄우고, 실제 구매가 진행되면 AbilityManager에서 뽑기를 실행하는 구조이다. 대략적인 흐름은 다음과 같다. ShopUI ↓ 구매 버튼 ↓ 구매 확인 Popup ↓ 재화 확인 ↓ AbilityManager ↓ Ability 추첨 ↓ 중복 처리 ↓ Ability 추가 ↓ JSON 저장 Basic / Rare / Legendary 등의 상자와 단일 구매 및 10회 구매를 연결하고 있다. 20. 개발 중 발견한 NullReferenceException Ability Shop을 구현하면서 중요한 문제도 발견했다. 구매 확정 버튼을 누르면 다음과 같은 오류가 발생했다. NullReferenceException: Object reference not set to an instance of an object AbilityManager.HandleDuplicate() AbilityManager.DrawBasicAbility() ShopUI.OnAbilityPurchaseButtonClicked() 처음에는 chestRarity 와 같은 값이 초기화되지 않은 문제를 의심했다. 하지만 실제 코드를 확인하면서 더 직접적인 원인을 찾을 수 있었다. GetRandomAbility() 는 해당 등급의 Ability가 하나도 없으면 null 을 반환한다. if (pool.Count == 0) return null; 그런데 이후 바로 HandleDuplicate(ability); 를 호출하고, HandleDuplicate() 내부에서 ability.abilityID 에 접근하고 있었다. 즉, GetRandomAbility() ↓ 해당 등급 Ability 없음 ↓ null 반환 ↓ HandleDuplicate(null) ↓ ability.abilityID 접근 ↓ NullReferenceException 이라는 흐름이었다. 이 문제를 통해 단순히 != null 체크를 어디에 추가할 것인가보다 null이 발생할 수 있는 데이터 흐름 자체를 먼저 확인해야 한다 는 것을 다시 확인했다. 21. 또 하나 확인한 구매 구조의 문제 Ability 구매 과정에서는 중복으로 Ability를 추가할 가능성도 확인했다. 현재 구매 과정에서 DrawBasicAbility() ├─ HandleDuplicate() └─ AddAbility() 가 실행되는 동시에 Shop의 다른 구매 처리에서도 AddAbility() 가 호출될 가능성이 있었다. 이 경우 한 번 구매했는데 Ability Count가 두 번 증가하는 문제가 발생할 수 있다. 따라서 현재는 단순히 오류 하나를 고치는 것뿐만 아니라, Ability를 실제로 획득하는 책임을 어디에서 담당할 것인지 를 다시 정리할 필요가 있는 상태이다. 22. 현재 프로젝트 구조 현재 Assets/Scripts 기준으로 보면 프로젝트가 상당히 여러 영역으로 분리되어 있다. Scripts ├─ Ability │ └─ AbilityData │ ├─ Clover │ └─ Clover │ ├─ Controll │ ├─ TouchController │ ├─ CameraJoystickMove │ └─ CameraMultiTouchMove │ ├─ Global │ ├─ BaseDepthSorter │ ├─ DynamicDepthSorter │ └─ StaticDepthSorter │ ├─ Growth │ └─ GrowthData │ ├─ Level │ └─ LevelData │ ├─ Manager │ ├─ GameManager │ ├─ CloverManager │ ├─ SpawnManager │ ├─ TouchManager │ ├─ AbilityManager │ ├─ GrowthManager │ ├─ GoldManager │ ├─ GemManager │ ├─ StarManager │ ├─ HourGlassManager │ ├─ AdsManager │ ├─ SoundManager │ ├─ HapticManager │ └─ UIManager │ ├─ Shop │ └─ DrawProbabilityTable │ └─ UI ├─ InGameUI ├─ GameEndUI ├─ ShopUI ├─ AbilityUI ├─ GrowthUI ├─ InventoryUI └─ ... 처음에는 하나의 게임을 만드는 것이 목적이었지만, 현재는 게임의 각 기능을 별도의 Manager와 Data 구조로 분리하는 형태로 발전했다. 23. 현재까지 개발하면서 배운 점 이번 프로젝트에서 가장 크게 느낀 점은 게임의 기능을 구현하는 것과 게임 시스템을 설계하는 것은 다른 문제 라는 것이다. 처음에는 클로버를 생성하고 터치하면 된다. 라고 생각했다. 하지만 실제로 개발해보니 다음과 같은 문제가 계속 추가되었다. 클로버 생성 ↓ 터치 판정 ↓ 모바일 UX ↓ 좌표계 ↓ 스테이지 ↓ 보상 ↓ 재화 ↓ 저장 ↓ 성장 ↓ 광고 ↓ Ability ↓ Shop ↓ Gacha 하나의 기능이 추가될 때마다 기존 시스템과 연결해야 했다. 특히 Manager가 많아지면서 어떤 시스템이 어떤 시스템의 데이터를 변경해야 하는지 가 중요해졌다. 24. 현재 FindClover의 상태 현재까지 구현된 시스템을 정리하면 다음과 같다. 게임 기본 시스템 클로버 생성 세잎 / 네잎클로버 구분 터치 입력 드래그 Depth Sorting 스테이지 제한 시간 게임 시작 / 종료 Pause Game End UI Title Option InGame UI Pause UI Game End UI Inventory Growth Shop Ability UI 재화 Gold Gem Star HourGlass 성장 Growth System Ability System Ability Upgrade Ability Slot 저장 JSON Save / Load 일일 보상 날짜 저장 광고 횟수 저장 Ability 데이터 저장 HourGlass 회복 시간 저장 광고 LevelPlay 보상형 광고 무료 보상 일일 광고 제한 Ability 광고 구매 Gold / Gem / HourGlass 광고 보상 상점 재화 구매 Ability Box 단일 구매 10회 구매 등급별 확률 뽑기 레벨 경험치 천장 시스템 까지 구현한 상태이다. 25. 앞으로 해결해야 할 부분 현재 가장 먼저 해결해야 하는 것은 Ability Shop의 구매 흐름이다. 특히 1. null Ability 처리 2. Ability 중복 획득 처리 3. 구매 → 추첨 → 저장 흐름 정리 4. 1회 / 10회 구매 로직 통합 5. 광고 구매와 일반 구매 로직 통합 을 우선적으로 정리할 예정이다. 그 이후에는 실제 모바일 환경에서의 테스트를 중심으로 진행할 필요가 있다. 특히 터치 판정과 UI 크기, 광고 보상, 저장 데이터, 앱 종료 후 데이터 복구 등을 실제 Android 환경에서 계속 확인할 예정이다. 마무리 FindClover는 처음에는 단순한 2D 클로버 찾기 게임 으로 시작했다. 하지만 지금은 게임 플레이 → 보상 → 재화 → 성장 → 능력 → 상점 → 뽑기 로 이어지는 하나의 게임 시스템을 갖추는 단계까지 발전했다. 이번 프로젝트에서 가장 의미 있었던 부분은 단순히 기능을 많이 구현했다는 것이 아니다. 처음에는 기능 하
인스턴스에 접속하려고 인터넷 전체에 SSH를 열어 놓으면 관리가 끝난 뒤에도 진입점이 남을 수 있습니다. 한편 웹 애플리케이션이 임의 URL을 요청하는 취약점은 관리 포트와 다른 경로로 인스턴스 정보를 노립니다. EC2 하드닝에서는 관리자의 접속 경로와 애플리케이션의 메타데이터 접근 을 따로 점검하겠습니다. 기존 AWS 시리즈 에서 서비스별 역할을 정리한 데 이어, 이번에는 정상 업무를 유지하면서 접근 범위를 줄이는 방법을 살펴봅니다. EC2, 보안 그룹, IAM 역할을 알고 있다는 전제입니다. 이번 예제는 일반 EC2 VM을 대상으로 하며 컨테이너의 모든 네트워크 형태를 포괄하지 않습니다. IMDS에는 무엇이 있나요? 인스턴스 메타데이터 서비스인 IMDS는 실행 중인 인스턴스가 자신의 정보를 조회하는 경로입니다. 인스턴스 역할의 임시 자격 증명도 이 경로와 관련됩니다. IMDSv2는 먼저 세션 토큰을 받은 뒤 그 토큰을 포함해 조회합니다. 인스턴스에서 토큰 사용을 required 로 설정하면 IMDSv1 방식은 사용할 수 없습니다. IMDSv2 동작 서버 측 요청 위조인 SSRF는 서버가 공격자가 유도한 주소로 요청하는 문제입니다. IMDSv2는 이 문제에 대한 방어를 보강하지만, 애플리케이션의 임의 URL 요청 취약점을 없애 주지는 않습니다. 대상 URL 제한, 리디렉션 처리, 인스턴스 역할의 최소 권한도 따로 검토합니다. 두 경로를 나눠 읽어 주세요. Session Manager를 사용했다고 IMDSv2가 자동 필수로 바뀌는 것은 아닙니다. IMDSv2를 필수로 해도 SSH 포트가 저절로 닫히지 않습니다. 메타데이터 옵션의 작은 예제 아래는 CloudFormation LaunchTemplate의 LaunchTemplateData 안에 넣는 속성 조각 입니다. 전체 인스턴스를 만드는 템플릿이 아닙니다. { "MetadataOptions": { "HttpEndpoint": "enabled", "HttpTokens": "required", "HttpPutResponseHopLimit": 1, "InstanceMetadataTags": "disabled" } } HttpTokens: required 가 IMDSv2 필수 설정입니다. 홉 제한은 응답이 이동할 수 있는 네트워크 홉에 관한 설정입니다. 일반 VM 예제에서는 1로 두었지만, 컨테이너 환경에서 이 값을 무조건 적용하면 필요한 메타데이터 요청이 실패할 수 있습니다. 실제 네트워크 구조와 사용 중인 SDK를 확인해야 합니다. MetadataOptions 필드 메타데이터 자체가 전혀 필요 없다면 엔드포인트 비활성화도 검토할 수 있습니다. 하지만 역할 자격 증명을 가져오는 SDK나 운영 도구의 의존성을 확인하지 않고 끄면 정상 작업을 막을 수 있습니다. 태그 공개 옵션 역시 태그 안에 비밀을 넣지 않는 원칙을 대신하지 않습니다. 관리 접속을 바꾸는 순서 Session Manager는 인바운드 관리 포트를 열지 않는 관리 경로를 제공합니다. 사용하려면 SSM Agent, 인스턴스와 운영자 IAM 권한, Systems Manager 서비스까지의 통신 경로를 준비해야 합니다. 인터넷 출구를 제거한 프라이빗 환경이라면 필요한 서비스 엔드포인트와 DNS도 확인합니다. Session Manager 개요 SSH를 먼저 닫고 새 경로를 준비하면 장애 때 접근할 수 없습니다. 테스트 인스턴스에서 접속, 권한 거부, 접속 종료, 감사 기록을 먼저 확인한 뒤 기존 인바운드 규칙을 줄입니다. 관리자의 세션 시작 권한도 모든 인스턴스가 아닌 업무 대상에 맞춥니다. 세션 내용을 항상 녹화한다고 생각하는 것도 위험합니다. SSH 방식이나 포트 포워딩 세션 등은 Session Manager의 세션 콘텐츠 로깅에 제한이 있습니다. 시작·종료 이력과 명령 내용 기록을 구분해 필요한 감사 범위를 설계해야 합니다. 이 글에서는 실제 세션 로깅을 시험하지 않았습니다. 세션 로그의 제한 변경 뒤 확인할 항목 SDK와 운영 도구가 IMDSv2를 지원하는지 확인합니다. 새 인스턴스뿐 아니라 현재 인스턴스의 메타데이터 옵션도 확인합니다. LaunchTemplate 수정이 기존 VM을 자동 변경했다고 가정하지 않습니다. 테스트 대상에서 토큰 없는 요청이 거부되고 정상 애플리케이션이 계속 동작하는지 확인합니다. 자격 증명 응답을 로그에 남기지 않습니다. 새 관리 경로가 동작한 뒤에 넓은 SSH 인바운드를 제거합니다. 되돌릴 경우에는 영향을 받은 옵션이나 관리 규칙만 검토된 이전 상태로 복구합니다. 전체 인터넷에 관리 포트를 여는 자동 원복을 피하고, 사전에 승인된 복구 경로를 사용합니다. IMDSv1 의존 도구가 발견됐다면 임시 예외의 대상과 종료 시점을 기록합니다. 로컬 검증: JSON 구문, IMDSv2 필수, VM 예제 홉 제한을 검사했습니다. HttpTokens 를 optional 로 바꾼 반례는 학습용 기준에서 탈락했습니다. 실제 EC2 요청, SSRF 방어 효과, Session Manager 접속과 감사 로그는 시험하지 않았습니다. 확인 문제 IMDSv2를 켜면 SSH가 자동으로 닫힐까요? 홉 제한 1을 모든 컨테이너 환경에 적용해도 될까요? 관리 포트를 없애기 전에 무엇을 확인해야 할까요? 답과 해설 아닙니다. 메타데이터와 관리 접속은 별개입니다. 아닙니다. 네트워크 홉과 SDK 의존성을 확인해야 합니다. Agent, IAM, 서비스 통신, 실제 새 관리 접속과 승인된 복구 경로입니다. 복습 오늘은 두 접근 경로를 나눠 그려 보세요. 내일은 기존 VM과 새 VM 중 어디에 설정이 적용됐는지 확인하는 질문을 써 보세요. 일주일 뒤에는 애플리케이션 역할을 줄이는 것이 SSRF의 피해에 어떤 영향을 주는지 설명해 보세요. 확인일: 2026-10-04, 한국 시간 . EC2 IMDSv2, CloudFormation LaunchTemplate, Systems Manager Session Manager 기준입니다.
관리 콘솔에 들어갈 수 있다는 것과, 매일 최고 권한으로 일해야 한다는 것은 다른 문제입니다. 배포 담당자에게 루트 계정이나 장기 액세스 키를 나눠 주면 업무가 끝난 뒤에도 같은 비밀이 남습니다. 이번 글에서는 누가 로그인하는지, 어떤 역할을 맡는지, 언제 권한이 끝나는지 를 분리해 보겠습니다. AWS 계정과 IAM 역할의 이름 정도를 알고 있으면 읽을 수 있습니다. 기존 AWS 시리즈 가 서비스 연결을 살펴봤다면, 여기서는 그 연결을 시작하는 사람의 접근부터 좁힙니다. 사람의 로그인과 프로그램의 로그인 사람은 IAM Identity Center나 외부 자격 증명 공급자를 통한 연동 로그인을 사용하고, 필요한 계정의 역할로 임시 자격 증명을 받는 흐름을 검토합니다. 프로그램은 사람이 쓰던 키를 복사하기보다 실행 환경에 맞는 IAM 역할을 사용합니다. 둘 다 장기 비밀을 줄이는 방향이지만 인증 방법까지 동일한 것은 아닙니다. IAM 보안 권장 사항 MFA는 다중 요소 인증입니다. 비밀번호만 알아서는 로그인할 수 없게 하는 추가 장치입니다. Identity Center의 자격 증명 원본이 무엇인지에 따라 MFA 설정 위치를 확인해야 합니다. 외부 IdP를 쓰면서 다른 화면의 MFA 체크만 켰다고 실제 사람의 로그인에 적용됐다고 판단하면 안 됩니다. 그림의 마지막 칸은 권한이 영구 저장되는 지점이 아닙니다. 역할 세션에는 수명이 있습니다. 다만 이미 발급된 세션의 처리와 새 로그인 차단은 별도로 확인해야 합니다. 계정 할당을 없앴다는 이유만으로 모든 세션이 즉시 끝났다고 가정하지 않습니다. 한 시간짜리 조회 역할의 예 아래 JSON은 CloudFormation의 AWS::SSO::PermissionSet 리소스 조각 입니다. 가상 ARN이며 배포용 전체 템플릿이 아닙니다. 실제 Identity Center 인스턴스, 사용자·그룹의 계정 할당, MFA 설정은 포함하지 않았습니다. { "Type": "AWS::SSO::PermissionSet", "Properties": { "InstanceArn": "arn:aws:sso:::instance/ssoins-0123456789abcdef", "Name": "StudyEc2Inventory", "SessionDuration": "PT1H", "InlinePolicy": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["ec2:DescribeInstances"], "Resource": "*" }] } } } PT1H 는 ISO 8601 형식의 한 시간입니다. 정책은 EC2 인스턴스 목록 조회만 예로 들었습니다. 이 조회 API는 리소스별 ARN으로 제한하는 방식이 지원되지 않아 Resource 가 * 입니다. 모든 작업을 허용하는 Action: "*" 와는 뜻이 다릅니다. 정책을 읽을 때 별표 하나만 보고 판단하기보다 작업별 지원 범위를 확인해야 합니다. PermissionSet 필드 , EC2 조회 권한의 리소스 제한 이 조각에는 MFA 조건이 없습니다. PermissionSet의 세션 시간 설정이 MFA 설정을 대신하지도 않습니다. 세션이 짧아져도 허용한 작업 자체가 줄어드는 것은 아니므로, 권한 범위와 세션 시간은 따로 검토합니다. 루트 계정은 비상 절차까지 함께 루트 계정은 일반 배포 계정으로 사용하지 않고, 루트가 필요한 작업의 절차를 분리합니다. 루트 액세스 키를 만들지 않고, MFA와 계정 복구 수단을 보호합니다. Organizations의 멤버 계정에서는 중앙 루트 접근 관리가 가능한 구성도 있지만, 독립 계정이나 관리 계정에 같은 절차를 그대로 적용할 수 있다고 가정하면 안 됩니다. 루트 사용자 보호 지침 운영 설계로는 비상 접근 담당자, 승인 방법, 사용 기록, 복구 수단을 정합니다. 정상 IdP가 장애일 때 필요한 경로까지 끊어 놓으면 보안 설정을 되돌릴 사람도 없어질 수 있습니다. 그렇다고 모두에게 상시 관리자 권한을 주는 방식으로 해결하지 않습니다. 적용·확인·되돌리기 현재 사람 계정, 장기 키 사용처, 루트 사용 이유를 목록으로 만듭니다. 비밀 값은 목록에 쓰지 않습니다. 테스트 계정에서 조회 역할을 할당하고 새 로그인에 MFA가 요구되는지 확인합니다. 인스턴스 조회는 성공하는지 확인합니다. 종료 권한 검사는 해당 API의 DryRun 으로 먼저 확인하고 실제 인스턴스를 종료하지 않습니다. 세션 만료 뒤 재인증도 별도 확인합니다. 기존 접근을 제거하기 전에 다른 승인된 관리 경로로 로그인할 수 있는지 점검합니다. 되돌릴 때는 변경한 할당이나 세션 설정을 검토된 이전 상태로 돌립니다. 장기 키를 다시 배포하는 것을 자동 복구 절차로 만들지 않습니다. 탈취된 자격 증명이라면 단순 원복보다 세션 처리와 사고 대응이 우선입니다. 로컬 검증: JSON 구문, 한 시간 세션, 조회 작업만 포함한 조건을 검사했습니다. 세션을 12시간으로 바꾼 반례가 학습용 기준에서 탈락하는 것도 확인했습니다. 실제 로그인, MFA 강제, STS 만료와 AWS 권한 평가는 실행하지 않았습니다. 확인 문제 MFA를 켜면 관리자 권한이 읽기 전용으로 바뀔까요? SessionDuration 을 줄이면 장기 액세스 키가 자동 삭제될까요? IdP 장애에 대비하는 절차에는 어떤 항목을 넣어야 할까요? 답과 해설 아닙니다. MFA는 인증을 보강하고, 허용 작업은 정책이 결정합니다. 아닙니다. 역할 세션 설정과 기존 키 수명은 별도입니다. 승인된 비상 신원, 접근 승인, 복구 수단, 사용 기록, 종료 후 권한 회수 방법입니다. 직접 로그인 검증도 필요합니다. 다시 공부하기 오늘은 사람과 워크로드의 로그인 경로를 따로 그려 보세요. 내일은 예제 역할이 조회만 할 수 있는지 정책을 읽어 보세요. 일주일 뒤에는 MFA와 최소 권한이 각각 막는 문제를 설명해 보세요. 권장 복습 순서이며 자동 알림은 아닙니다. 문서 확인일: 2026-10-04, 한국 시간 . 예제 기준은 IAM Identity Center PermissionSet과 IAM 정책 2012-10-17 입니다. 다음 학습 목표는 역할의 신뢰 정책과 실제 작업 권한을 구분하는 것입니다.
작성일: 2026-10-04 오늘의 학습 키워드 .tag { display:inline-block; background:#f1f3f5; border-radius:16px; padding:4px 12px; margin:4px; font-size:14px; } .tag-group h4 { margin-bottom:6px; } Java 개요 Java Python Backend Spring Boot 객체 지향 OOP Class Instance Variable Method 실행 환경 JDK JRE JVM 오늘 공부한 내용 키워드1: Java를 배우는 이유 개념 정리 개발에서 자주 쓰이는 언어로 Python과 Java를 꼽을 수 있는데, 둘은 주로 쓰이는 영역이 다르다. Python은 라이브러리가 풍부해서 AI, 데이터 분석, 데이터 사이언스 쪽에서 강점을 가진다. 반면 Java는 국내 공공기관, 금융권, 기업 내부 시스템에서 많이 쓰이는 언어로, 특히 백엔드 영역과 Spring Boot 기반 웹 애플리케이션 개발에서 자주 등장한다. 웹 서비스는 프론트엔드와 백엔드로 나뉘는데, 프론트엔드가 사용자에게 보여지는 화면을 담당한다면 백엔드는 데이터를 처리하고 그 결과를 응답으로 돌려주는 역할을 한다. 프론트엔드는 데이터를 직접 가지고 있지 않기 때문에, 필요한 데이터는 백엔드와 통신해서 받아온다. Java, 그중에서도 Spring Boot는 이런 백엔드 쪽에서 프론트엔드의 요청을 처리하고 DB와 연동해 응답을 만드는 역할을 한다. Python → AI / 데이터 분석 / 데이터 사이언스 Java → 백엔드 / 공공기관 / 금융권 / 기업 시스템 Java + Spring Boot → 웹 백엔드 서버 개발 용어 정리 / 주의점 Python과 Java를 "어떤 분야에 강점이 있는가"로 구분해서 기억 프론트엔드는 데이터를 직접 안 갖고 있고, 백엔드와 통신해서 받아온다는 흐름 기억 키워드2: 객체 지향, Class와 Instance 개념 정리 Java는 객체 지향 프로그래밍(OOP, Object-Oriented Programming) 언어다. 객체 지향은 현실에 존재하는 사물이나 개념(학생, 자동차, 계좌, 회원 등)을 프로그램 안에서 객체로 표현하려는 방식이다. 이런 객체는 각각 명사적인 특징(이름, 이메일, 나이 같은 속성)과 동사적인 특징(로그인하다, 회원가입하다 같은 행동)을 가진다. Class는 이런 객체를 만들기 위한 템플릿, 즉 설계도다. 현실의 객체를 그대로 프로그램에 가져올 수 없기 때문에, 그 객체의 특징과 동작을 코드로 정의해둔 것이 Class다. Class 안에서 명사적인 특징은 Variable(변수)로, 동사적인 특징은 Method(메서드)로 표현한다. Instance는 이 Class를 바탕으로 실제로 만들어진 객체를 말한다. 예를 들어 Student라는 Class가 설계도라면, 그 설계도로 만들어낸 student1, student2 같은 실제 객체가 Instance다. Class는 설계도, Instance는 그 설계도로 찍어낸 실물이라는 비유로 구분하면 헷갈리지 않는다. Class(설계도) → Student Instance(실제 객체) → student1, student2 ... Class 안 구성: Variable(속성) + Method(동작) 용어 정리 / 주의점 Class = 설계도 / 템플릿, Instance = 그 설계도로 만든 실제 객체 Variable = 명사적 특징(속성), Method = 동사적 특징(동작) 키워드3: 개발 환경이 필요한 이유, JDK/JRE/JVM 개념 정리 VS Code는 코드를 작성하는 편집기일 뿐이고, Java 코드를 실제로 실행하려면 별도의 실행 환경이 필요하다. 이를 위해 설치하는 것이 JDK(Java Development Kit)로, Java 개발에 필요한 도구 모음이라고 이해하면 된다. JDK를 설치하면 코드를 컴파일하고 실행할 수 있는 환경이 갖춰진다. JDK, JRE, JVM은 포함 관계로 이해할 수 있다. JDK(Java 개발 도구) 안에는 JRE(Java 실행 환경)가 포함되고, JRE 안에는 JVM(Java 가상 머신)이 포함된다. Java 프로그램은 운영체제 위에서 직접 실행되는 게 아니라 이 JVM 위에서 실행된다. 이 구조 덕분에 Java는 플랫폼 독립성이라는 특징을 갖는다. 일반적인 프로그램은 운영체제에 따라 실행 방식이 달라질 수 있지만, Java 프로그램은 JVM 위에서 동작하기 때문에 운영체제가 달라도 그 환경에 맞는 JVM만 설치돼 있으면 같은 Java 프로그램을 실행할 수 있다. 이를 "Write Once, Run Anywhere"라는 말로 표현한다. JDK (개발 도구) └ JRE (실행 환경) └ JVM (가상 머신) ← Java 프로그램이 실제로 실행되는 곳 Java 프로그램 → JVM 위에서 실행 → OS에 직접 의존하지 않음 용어 정리 / 주의점 JDK ⊃ JRE ⊃ JVM 포함 관계로 기억 "Write Once, Run Anywhere" = JVM만 있으면 어디서든 같은 코드 실행 가능하다는 의미 키워드4: JDK 버전 선택 개념 정리 JDK는 배포 주체와 버전에 따라 여러 종류가 있는데, 대표적으로 Oracle JDK, OpenJDK, Eclipse Temurin JDK 등이 있다. Spring Boot를 함께 공부할 계획이라면 JDK 버전 선택이 중요한데, Spring Boot 3.x 버전부터는 Java 17 이상을 요구하기 때문이다. 현업에서는 LTS(장기 지원) 버전인 Java 11도 많이 쓰이지만, 최신 Spring Boot 학습을 기준으로는 Java 17을 기준으로 잡는 게 적절하다. Java 11 → 현업에서 많이 쓰는 LTS 버전 Java 17 → Spring Boot 3.x 학습에 적합한 LTS 버전 Java 21 → 비교적 최신 LTS 버전 용어 정리 / 주의점 Spring Boot 3.x = Java 17 이상 필요하다는 점이 버전 선택의 기준 현업 버전(Java 11)과 학습 기준 버전(Java 17)이 다를 수 있다는 점 참고 오늘의 회고 오늘 내용은 대학교 때 배운 걸 그대로 복습하는 느낌이었다. Java, OOP, Class, Instance, JDK/JRE/JVM까지 전부 이미 알고 있는 개념이라 새로 이해해야 할 부분은 거의 없었다. 그래서 오늘은 "내가 아는가"보다 "이걸 모르는 사람한테 어떻게 설명할 것인가"에 더 집중해서 정리해봤다. 막상 설명하려고 보니, 알고 있다고 생각했던 개념도 말로 풀어내려면 생각보다 단어 선택이 까다로웠다. 특히 Class와 Instance를 "설계도와 실제 객체"로 비유하는 부분이나, JDK/JRE/JVM을 포함 관계로 짚는 부분은 알고는 있었지만 누군가에게 처음 설명하는 입장에서 다시 다듬어본 느낌이다. 다음에도 이런 복습성 내용이 나오면, 내용을 늘리기보다 어떻게 하면 더 쉽게 전달할 수 있을지를 기준으로 정리해봐야겠다. 내일 학습 계획 및 후기 [ Java 2강 - 변수와 자료형]
1. 프로젝트 기획 및 아키텍처 설계 0. 들어가기 전.. 보통 저는 잠에 들기 전 핸드폰을 보고 잡니다. 어릴 때부터 어두운 곳에서 핸드폰을 하면 눈이 나빠진다는 어머니의 가스라이팅 때문에 저는 잠에 들기 전까지 방에 불을 켜고 있습니다. 그렇기에 핸드폰을 하다가 잠이 오면 불을 끄러 침대에서 일어나 불을 끄고 자곤 했습니다. 하지만 불을 끄러 일어나는 순간 잠에서 깨곤 합니다. 이러한 불편함을 제거하면서 제가 배운 것을 사용할 기회라고 생각하며 이번 프로젝트를 진행하려고 합니다. 이번 포스팅은 프로젝트의 전체적인 기획과 시스템 아키텍처 설계 내용입니다. 1. 프로젝트 개요 및 목표 본 프로젝트의 공식 명칭은 'Siri 연동 스마트홈 스위치봇 시스템' 입니다. 주요 개발 목적은 다음과 같습니다. IoT 인프라 구축: Apple HomeKit(Siri) 생태계를 기반으로 물리 벽면 스위치를 원격 제어할 수 있는 시스템 구축. 펌웨어 설계 역량 확보: ESP-IDF(C/C++) 및 FreeRTOS 기반의 멀티태스킹 펌웨어 설계. 기구부 맞춤 설계: 3D 프린팅(PLA)을 활용한 맞춤형 기구부 설계 및 조립. QA 및 신뢰성 검증: ISTQB 표준에 입각한 임베디드 소프트웨어 단위/통합/시스템 테스트 파이프라인 구축 및 신뢰성 검증. 저는 아이폰 13미니를 사용 중이라 Apple HomeKit 생태계를 기반으로 시스템을 구축해보겠습니다. 2. 하드웨어 및 기구 설계 (Mechanical Design) 제한된 크기 안에서 배터리 구동 효율과 강력한 물리적 타격을 동시에 확보하기 위해 다음과 같은 하드웨어 및 기구부 구조를 설계했습니다. 2.1. 핵심 하드웨어 구성 MCU: 초소형 폼팩터와 Wi-Fi를 지원하는 ESP32-C3 Supermini 개발 보드. 전원 및 확장: 충전 회로 및 JST PH2.0 커넥터가 내장된 ESP32-C3 전용 Expansion board. 배터리: Soshine 3.7V 803040 1000mAh LIPO 배터리. 액추에이터: 내구성을 위해 모든 메탈 기어가 적용된 MG90S 서보 모터. 부품은 알리에서 주문했습니다. 2개 만들 생각으로 총 3만원 이내로 구매했습니다. 2.2. 3D 기구 설계 전략 Autodesk Fusion 360을 활용하여 설계하며, 출력 소재는 실내 기구물에 적합한 PLA를 사용합니다. 가장 중요한 스위치 대응 전략으로, 시소형(Rocker) 스위치의 가로 방향 구조를 고려하여 스위치의 좌측과 우측에 스위치봇을 각각 1개씩 부착하여 단방향 누름(Push)만 수행하도록 설계 했습니다. 설계된 파트는 총 4가지로 구성됩니다. Main Housing (본체 케이스): ESP32-C3 보드, 확장 보드, 배터리를 층상으로 수납하고 외부 Type-C 충전 포트가 노출되는 슬롯 구조. Motor Mount Bracket (모터 마운트): MG90S 서보모터를 흔들림 없이 고정하는 브래킷. Pusher Arm (구동부 레버): 서보모터 기어 축에 결합되어 회전 운동을 수직 누름 힘으로 변환하여 스위치를 직접 타격하는 모멘트 암. Base Plate (부착 베이스): 3M VHB 초강력 양면테이프를 이용하여 벽면 스위치 커버 프레임(좌/우)에 밀착 고정되는 마운팅 파트. 3. 소프트웨어 및 펌웨어 아키텍처 시스템은 크게 HomeKit 연동을 담당하는 '메인 허브'와, 실제 물리적인 동작을 수행하는 '스위치봇(Edge Device)'으로 나뉩니다. 3.1. 메인 허브 (Raspberry Pi) OS: Linux (Raspberry Pi OS). 핵심 서비스: Homebridge 구동 및 systemd 데몬 등록을 통한 자동 재시작 보장. 통신 브로커: Eclipse Mosquitto (MQTT Broker) 구동. 3.2. 스위치봇 펌웨어 (ESP-IDF C/C++) FreeRTOS 멀티태스킹 아키텍처를 적용하여 통신과 하드웨어 제어를 철저히 분리합니다. 네트워크 태스크 (MQTT Event Handler): Wi-Fi 연결을 유지하며 라즈베리파이 브로커로부터 특정 토픽(예: home/switch/left/set )의 메시지를 수신합니다. 명령 수신 시 큐(Queue)를 통해 제어 명령을 전달합니다. 하드웨어 제어 태스크 (Servo Control): 평소에는 대기(Block) 상태를 유지하다가, 큐를 통해 명령이 들어오면 ledc 하드웨어 타이머 드라이버를 이용해 지터(Jitter) 없이 고정밀 PWM 신호를 생성합니다. 지정된 각도로 스위치 타격 후 0도로 원복합니다. 전력 관리 전략: 배터리 구동 효율을 극대화하기 위해 Wi-Fi 연결을 유지한 채 전력 소모를 최소화하는 Modem Sleep (Light Sleep) 모드를 적용합니다. 4. 임베디드 SW 테스팅 및 QA 전략 단순히 동작하는 기기를 만드는 것을 넘어, 시스템의 신뢰성과 예외 상황 대처 능력을 입증하기 위해 체계적인 품질 보증 프로세스를 거칠 예정입니다. 4.1. 단위 테스트 (Unit Test) 도구 & 기법: ESP-IDF 내장 Unity Test Framework를 사용하며, 동등 분할(Equivalence Partitioning) 및 경계값 분석(Boundary Value Analysis) 기법을 적용합니다. 검증 대상: MQTT 페이로드 파서(Parser)가 정의되지 않은 문자열이나 특수문자, 초과된 길이의 데이터를 수신했을 때 버퍼 오버플로우나 예외 없이 안전하게 폐기(Drop)하는지 검증합니다. 또한 서보모터 회전 각도 산출 함수의 경계값 정상 처리 여부를 확인합니다. 4.2. 통합 테스트 (Integration Test) 도구: MQTT.fx, Postman, Wireshark. 검증 대상: 라즈베리파이(Mosquitto Broker)와 ESP32-C3 간의 Publish/Subscribe 통신 흐름을 검증합니다. 네트워크 순단 시 ESP32-C3의 자동 재연결(Auto-reconnect) 루틴 정상 작동 및 Homebridge 상태 동기화 지연 시간(Latency)을 측정합니다. 4.3. 시스템 및 신뢰성 테스트 (System/Stress Test) 결함 주입 (Fault Injection): 모터가 스위치를 누르는 순간 고부하로 인한 전압 강하(Brownout) 상황을 의도적으로 모사하여, ESP32-C3가 하드웨어 폴트 없이 안전하게 워치독(Watchdog) 리셋 후 정상 구동 상태로 복귀하는지(Fail-safe) 검증합니다. 메모리 누수 모니터링: 24시간 연속 운용 및 1,000회 이상의 연속 제어 명령 하달 시 esp_get_free_heap_size() 를 통해 Heap 메모리 누수(Leak)가 발생하는지 추적합니다.