diff --git a/build.gradle b/build.gradle
index b88f4542cc05422dcee3e5491eb9d93ed75f7ec7..1b29e4ade60f1ece03c8e7680004ea772cfc1ef3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -30,12 +30,19 @@ dependencies {
     compileOnly 'org.projectlombok:lombok'
     runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
     runtimeOnly 'com.mysql:mysql-connector-j'
-    implementation 'org.pacesys:openstack4j:3.1.0'
     annotationProcessor 'org.projectlombok:lombok'
     testImplementation 'org.springframework.boot:spring-boot-starter-test'
     testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
+    implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
+    annotationProcessor "jakarta.annotation:jakarta.annotation-api"
+    annotationProcessor "jakarta.persistence:jakarta.persistence-api"
+    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
+
 }
 
 tasks.named('test') {
     useJUnitPlatform()
 }
+clean {
+    delete file('src/main/generated')
+}
\ No newline at end of file
diff --git a/src/main/java/com/aolda/itda/aspect/ForwardingLogAspect.java b/src/main/java/com/aolda/itda/aspect/ForwardingLogAspect.java
new file mode 100644
index 0000000000000000000000000000000000000000..d50c2feaaedc63a3b5dbac4fa28666ee146ca2a0
--- /dev/null
+++ b/src/main/java/com/aolda/itda/aspect/ForwardingLogAspect.java
@@ -0,0 +1,155 @@
+package com.aolda.itda.aspect;
+
+import com.aolda.itda.dto.forwarding.ForwardingDTO;
+import com.aolda.itda.entity.forwarding.Forwarding;
+import com.aolda.itda.entity.log.Action;
+import com.aolda.itda.entity.log.Log;
+import com.aolda.itda.entity.log.ObjectType;
+import com.aolda.itda.entity.user.User;
+import com.aolda.itda.exception.CustomException;
+import com.aolda.itda.exception.ErrorCode;
+import com.aolda.itda.repository.certificate.CertificateRepository;
+import com.aolda.itda.repository.forwarding.ForwardingRepository;
+import com.aolda.itda.repository.log.LogRepository;
+import com.aolda.itda.repository.routing.RoutingRepository;
+import com.aolda.itda.repository.user.UserRepository;
+import com.aolda.itda.service.AuthService;
+import jakarta.persistence.EntityManager;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.util.Map;
+import java.util.Objects;
+
+@Aspect
+@Component
+@RequiredArgsConstructor
+public class ForwardingLogAspect {
+
+    private final ForwardingRepository forwardingRepository;
+    private final LogRepository logRepository;
+    private final EntityManager entityManager;
+    private final UserRepository userRepository;
+
+    /* Create 로깅 */
+    @AfterReturning(pointcut = "execution(* com.aolda.itda.service.forwarding.*Service.*create*(..))"
+    , returning = "result")
+    public void createLogging(JoinPoint joinPoint, ForwardingDTO result) {
+
+        /* 사용자 조회 */
+        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+        Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
+        User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
+                () -> new CustomException(ErrorCode.NOT_FOUND_USER)
+        );
+
+        /* 생성된 엔티티 조회 */
+        Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(result.getId(), false).orElse(null);
+
+        /* 로그 메세지 작성 */
+        String description = "name: " + forwarding.getName() + "\n"
+                + "serverPort: " + forwarding.getServerPort() + "\n"
+                + "instanceIp: " + forwarding.getInstanceIp() + "\n"
+                + "instancePort: " + forwarding.getInstancePort();
+
+        /* 로그 엔티티 저장 */
+        logRepository.save(Log.builder()
+                .user(user)
+                .objectType(ObjectType.FORWARDING)
+                .objectId(forwarding.getForwardingId())
+                .action(Action.CREATE)
+                .projectId(forwarding.getProjectId())
+                .description(description)
+                .build());
+    }
+
+    /* Delete 로깅 */
+    @AfterReturning(pointcut = "execution(* com.aolda.itda.service.forwarding.*Service.*delete*(..))")
+    public void deleteLogging(JoinPoint joinPoint) {
+        
+        /* 사용자 조회 */
+        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+        Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
+        User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
+                () -> new CustomException(ErrorCode.NOT_FOUND_USER)
+        );
+
+        /* 삭제된 엔티티 조회 */
+        Object[] args = joinPoint.getArgs();
+
+        Long id = (Long) args[0];
+        Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(id, true).orElse(null);
+
+        /* 로그 메세지 작성 */
+        String description = "name: " + forwarding.getName() + "\n"
+                + "serverPort: " + forwarding.getServerPort() + "\n"
+                + "instanceIp: " + forwarding.getInstanceIp() + "\n"
+                + "instancePort: " + forwarding.getInstancePort();
+
+        /* 로그 엔티티 저장 */
+        logRepository.save(Log.builder()
+                .user(user)
+                .objectType(ObjectType.FORWARDING)
+                .objectId(forwarding.getForwardingId())
+                .action(Action.DELETE)
+                .projectId(forwarding.getProjectId())
+                .description(description)
+                .build());
+    }
+
+    /* Update(edit) 로깅 */
+    @Around("execution(* com.aolda.itda.service.forwarding.*Service.*edit*(..))")
+    public Object editLogging(ProceedingJoinPoint joinPoint) throws Throwable {
+        
+        /* 사용자 조회 */
+        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+        Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
+        User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
+                () -> new CustomException(ErrorCode.NOT_FOUND_USER)
+        );
+
+        /* 변경 전 엔티티 조회 */
+        Object[] args = joinPoint.getArgs();
+
+        Long id = (Long) args[0];
+        Forwarding old = forwardingRepository.findByForwardingIdAndIsDeleted(id, false).orElse(null);
+        if (old != null) {
+            entityManager.detach(old);
+        }
+        
+        /* 메소드 진행 */
+        Object result = joinPoint.proceed();
+
+        /* 변경 후 엔티티 조회*/
+        Forwarding newObj = forwardingRepository.findByForwardingIdAndIsDeleted(id, false).orElse(null);
+        
+        /* 로그 메세지 작성 */
+        String description = "name: " + old.getName() + (old.getName().equals(newObj.getName()) ? "" : (" -> " + newObj.getName())) + "\n"
+                + "serverPort: " + old.getServerPort() + (old.getServerPort().equals(newObj.getServerPort()) ? "" : (" -> " + newObj.getServerPort())) + "\n"
+                + "instanceIp: " + old.getInstanceIp() + (old.getInstanceIp().equals(newObj.getInstanceIp()) ? "" : (" -> " + newObj.getInstanceIp())) + "\n"
+                + "instancePort: " + old.getInstancePort() + (old.getInstancePort().equals(newObj.getInstancePort()) ? "" : (" -> " + newObj.getInstancePort()));
+
+        /* 로그 엔티티 저장 */
+        logRepository.save(Log.builder()
+                .user(user)
+                .objectType(ObjectType.FORWARDING)
+                .objectId(newObj.getForwardingId())
+                .action(Action.UPDATE)
+                .projectId(newObj.getProjectId())
+                .description(description)
+                .build());
+        return result;
+    }
+
+
+
+}
diff --git a/src/main/java/com/aolda/itda/aspect/RoutingLogAspect.java b/src/main/java/com/aolda/itda/aspect/RoutingLogAspect.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3a67d2dce9f65af87807d2c758eb3a225090b32
--- /dev/null
+++ b/src/main/java/com/aolda/itda/aspect/RoutingLogAspect.java
@@ -0,0 +1,170 @@
+package com.aolda.itda.aspect;
+
+import com.aolda.itda.dto.forwarding.ForwardingDTO;
+import com.aolda.itda.dto.routing.RoutingDTO;
+import com.aolda.itda.entity.forwarding.Forwarding;
+import com.aolda.itda.entity.log.Action;
+import com.aolda.itda.entity.log.Log;
+import com.aolda.itda.entity.log.ObjectType;
+import com.aolda.itda.entity.routing.Routing;
+import com.aolda.itda.entity.user.User;
+import com.aolda.itda.exception.CustomException;
+import com.aolda.itda.exception.ErrorCode;
+import com.aolda.itda.repository.forwarding.ForwardingRepository;
+import com.aolda.itda.repository.log.LogRepository;
+import com.aolda.itda.repository.routing.RoutingRepository;
+import com.aolda.itda.repository.user.UserRepository;
+import jakarta.persistence.EntityManager;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.util.Map;
+import java.util.Objects;
+
+@Aspect
+@Component
+@RequiredArgsConstructor
+public class RoutingLogAspect {
+
+    private final RoutingRepository routingRepository;
+    private final UserRepository userRepository;
+    private final LogRepository logRepository;
+    private final EntityManager entityManager;
+
+    /* Create 로깅 */
+    @AfterReturning(pointcut = "execution(* com.aolda.itda.service.routing.*Service.*create*(..))"
+            , returning = "result")
+    public void createLogging(JoinPoint joinPoint, RoutingDTO result) {
+
+        /* 사용자 조회 */
+        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+        Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
+        User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
+                () -> new CustomException(ErrorCode.NOT_FOUND_USER)
+        );
+
+        /* 생성된 엔티티 조회 */
+        Routing routing = routingRepository.findByRoutingIdAndIsDeleted(result.getId(), false).orElse(null);
+
+        /* 로그 메세지 작성 */
+        String description = "name: " + routing.getName() + "\n"
+                + "domain: " + routing.getDomain() + "\n"
+                + "ip: " + routing.getInstanceIp() + "\n"
+                + "port: " + routing.getInstancePort() + "\n"
+                +  (routing.getCertificate() != null ? ("certificateId: " + routing.getCertificate().getCertificateId() + "\n") : "")
+                + "caching: " + routing.getCaching() + "\n";
+
+        /* 로그 엔티티 저장 */
+        logRepository.save(Log.builder()
+                .user(user)
+                .objectType(ObjectType.ROUTING)
+                .objectId(routing.getRoutingId())
+                .action(Action.CREATE)
+                .projectId(routing.getProjectId())
+                .description(description)
+                .build());
+    }
+
+    /* Delete 로깅 */
+    @AfterReturning(pointcut = "execution(* com.aolda.itda.service.routing.*Service.*delete*(..))")
+    public void deleteLogging(JoinPoint joinPoint) {
+
+        /* 사용자 조회 */
+        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+        Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
+        User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
+                () -> new CustomException(ErrorCode.NOT_FOUND_USER)
+        );
+
+        /* 삭제된 엔티티 조회 */
+        Object[] args = joinPoint.getArgs();
+
+        Long id = (Long) args[0];
+        Routing routing = routingRepository.findByRoutingIdAndIsDeleted(id, true).orElse(null);
+
+        /* 로그 메세지 작성 */
+        String description = "name: " + routing.getName() + "\n"
+                + "domain: " + routing.getDomain() + "\n"
+                + "ip: " + routing.getInstanceIp() + "\n"
+                + "port: " + routing.getInstancePort() + "\n"
+                +  (routing.getCertificate() != null ? ("certificateId: " + routing.getCertificate().getCertificateId() + "\n") : "")
+                + "caching: " + routing.getCaching() + "\n";
+
+        /* 로그 엔티티 저장 */
+        logRepository.save(Log.builder()
+                .user(user)
+                .objectType(ObjectType.ROUTING)
+                .objectId(routing.getRoutingId())
+                .action(Action.DELETE)
+                .projectId(routing.getProjectId())
+                .description(description)
+                .build());
+    }
+
+    /* Update(edit) 로깅 */
+    @Around("execution(* com.aolda.itda.service.routing.*Service.*edit*(..))")
+    public Object editLogging(ProceedingJoinPoint joinPoint) throws Throwable {
+
+        /* 사용자 조회 */
+        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+        Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
+        User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
+                () -> new CustomException(ErrorCode.NOT_FOUND_USER)
+        );
+
+        /* 변경 전 엔티티 조회 */
+        Object[] args = joinPoint.getArgs();
+
+        Long id = (Long) args[0];
+        Routing old = routingRepository.findByRoutingIdAndIsDeleted(id, false).orElse(null);
+        if (old != null) {
+            entityManager.detach(old);
+        }
+
+        /* 메소드 진행 */
+        Object result = joinPoint.proceed();
+
+        /* 변경 후 엔티티 조회 */
+        Routing newObj = routingRepository.findByRoutingIdAndIsDeleted(id, false).orElse(null);
+
+        /* 로그 메세지 작성 */
+        String description = "name: " + old.getName() + (old.getName().equals(newObj.getName()) ? "" : " -> " + newObj.getName()) + "\n"
+                + "domain: " + old.getDomain() + (old.getDomain().equals(newObj.getDomain()) ? "" : " -> " + newObj.getDomain()) + "\n"
+                + "ip: " + old.getInstanceIp() + (old.getInstanceIp().equals(newObj.getInstanceIp()) ? "" : " -> " + newObj.getInstanceIp()) + "\n"
+                + "port: " + old.getInstancePort() + (old.getInstancePort().equals(newObj.getInstancePort()) ? "" : " -> " + newObj.getInstancePort()) + "\n";
+        if (old.getCertificate() == null) {
+            if (newObj.getCertificate() != null) {
+                description = description + "certificateId: null -> " + newObj.getCertificate().getCertificateId() + "\n";
+            }
+        }
+        else {
+            if (newObj.getCertificate() == null) {
+                description = description + "certificateId: " + old.getCertificate().getCertificateId() + " -> null\n";
+            }
+            else {
+                description = description + "certificateId: " + old.getCertificate().getCertificateId() + " -> " + newObj.getCertificate().getCertificateId() + "\n";
+            }
+        }
+        description = description + "caching: " + (old.getCaching() == newObj.getCaching() ? newObj.getCaching() : (" -> " + newObj.getCaching()));
+
+        /* 로그 엔티티 저장 */
+        logRepository.save(Log.builder()
+                .user(user)
+                .objectType(ObjectType.ROUTING)
+                .objectId(newObj.getRoutingId())
+                .action(Action.UPDATE)
+                .projectId(newObj.getProjectId())
+                .description(description)
+                .build());
+        return result;
+    }
+}
diff --git a/src/main/java/com/aolda/itda/config/AuthInterceptor.java b/src/main/java/com/aolda/itda/config/AuthInterceptor.java
index 63f2320e18fa92cd2edb275561be760518b19cc1..3a95f8a4e329d27457a75d18fac600f6fe84a836 100644
--- a/src/main/java/com/aolda/itda/config/AuthInterceptor.java
+++ b/src/main/java/com/aolda/itda/config/AuthInterceptor.java
@@ -1,5 +1,6 @@
 package com.aolda.itda.config;
 
+import com.aolda.itda.dto.auth.IdAndNameDTO;
 import com.aolda.itda.exception.CustomException;
 import com.aolda.itda.exception.ErrorCode;
 import com.aolda.itda.service.AuthService;
@@ -10,6 +11,9 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 import org.springframework.web.servlet.HandlerInterceptor;
 
+import java.util.List;
+import java.util.Map;
+
 @RequiredArgsConstructor
 @Component
 @Slf4j
@@ -20,18 +24,44 @@ public class AuthInterceptor implements HandlerInterceptor {
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
         String token = request.getHeader("X-Subject-Token");
+
+        /* 토큰 헤더 검증 */
         if (token == null || token.isEmpty()) {
             throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI());
         }
-        // 어드민과 일반 유저 구분 필요
-        try {
-            if (authService.validateTokenAndGetUserId(token) != null) {
-                return true;
-            }
-        } catch (Exception e) {
-            log.error("Token validation failed for URI {}: {}", request.getRequestURI(), e.getMessage(), e);
+
+        /* 유효 토큰 검증 */
+        String userId = authService.validateTokenAndGetUserId(token);
+        if (userId == null) {
+            log.error("Token validation failed for URI {}: {}", request.getRequestURI(), request.getRemoteAddr());
             throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI());
         }
-        throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI());
+
+        /* 프로젝트 권한 검증 */
+        String projectId = request.getParameter("projectId");
+        if (projectId != null) {
+
+            try {
+                String role = authService.getBestRoleWithinProject(token, projectId).get("role");
+                if (!role.equals("admin")) {
+                    log.error("Unauthorized Token for URI {}: {}", request.getRequestURI(), request.getRemoteAddr());
+                    throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI());
+                }
+            } catch (Exception e) {
+                throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI());
+            }
+
+
+
+        }
+
+        /* 프로젝트 리스트 조회 */
+        List<String> projects = authService.getProjectsWithUser(Map.of("id", userId, "token", token))
+                        .stream().map(IdAndNameDTO::getId)
+                        .toList();
+        request.setAttribute("projects", projects);
+        request.setAttribute("user", Map.of("id", userId, "token", token));
+        return true;
+
     }
 }
diff --git a/src/main/java/com/aolda/itda/config/WebConfig.java b/src/main/java/com/aolda/itda/config/WebConfig.java
index 71e134bebee94ab01c47d0a032e6026d9929b62b..e3893aeecd8b181adc3bc069fbb7724fef9c38ab 100644
--- a/src/main/java/com/aolda/itda/config/WebConfig.java
+++ b/src/main/java/com/aolda/itda/config/WebConfig.java
@@ -1,6 +1,9 @@
 package com.aolda.itda.config;
 
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import jakarta.persistence.EntityManager;
 import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.CorsRegistry;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@@ -25,10 +28,15 @@ public class WebConfig implements WebMvcConfigurer {
 
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
-        String[] excludeAuth = {"/error", "/api/auth/*", "/api/*" };
+        String[] excludeAuth = {"/error", "/api/auth/*" };
 
         registry.addInterceptor(authInterceptor)
                 .addPathPatterns("/**")
                 .excludePathPatterns(excludeAuth);
     }
+
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager em) {
+        return new JPAQueryFactory(em);
+    }
 }
diff --git a/src/main/java/com/aolda/itda/controller/forwarding/ForwardingController.java b/src/main/java/com/aolda/itda/controller/forwarding/ForwardingController.java
index a6b67ecbd0090ce8f8460d3fd8b08def88d520a8..36e6f9a8138da9fee0f76d6028770260d9fb5679 100644
--- a/src/main/java/com/aolda/itda/controller/forwarding/ForwardingController.java
+++ b/src/main/java/com/aolda/itda/controller/forwarding/ForwardingController.java
@@ -2,11 +2,14 @@ package com.aolda.itda.controller.forwarding;
 
 import com.aolda.itda.dto.forwarding.ForwardingDTO;
 import com.aolda.itda.service.forwarding.ForwardingService;
+import jakarta.servlet.http.HttpServletRequest;
 import jakarta.validation.Valid;
 import lombok.RequiredArgsConstructor;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.List;
+
 @RestController
 @RequestMapping("/api")
 @RequiredArgsConstructor
@@ -22,8 +25,8 @@ public class ForwardingController {
     }
 
     @GetMapping("/forwarding")
-    public ResponseEntity<Object> view(@RequestParam Long forwardingId) {
-        return ResponseEntity.ok(forwardingService.getForwarding(forwardingId));
+    public ResponseEntity<Object> view(@RequestParam Long forwardingId, HttpServletRequest request) {
+        return ResponseEntity.ok(forwardingService.getForwarding(forwardingId, (List<String>) request.getAttribute("projects")));
     }
 
     @GetMapping("/forwardings")
@@ -33,14 +36,16 @@ public class ForwardingController {
 
     @PatchMapping("/forwarding")
     public ResponseEntity<Object> edit(@RequestParam Long forwardingId,
-                                         @RequestBody ForwardingDTO dto) {
-        forwardingService.editForwarding(forwardingId, dto);
+                                         @RequestBody ForwardingDTO dto,
+                                       HttpServletRequest request) {
+        forwardingService.editForwarding(forwardingId, dto, (List<String>) request.getAttribute("projects") );
         return ResponseEntity.ok().build();
     }
 
     @DeleteMapping("/forwarding")
-    public ResponseEntity<Object> delete(@RequestParam Long forwardingId) {
-        forwardingService.deleteForwarding(forwardingId);
+    public ResponseEntity<Object> delete(@RequestParam Long forwardingId,
+                                         HttpServletRequest request) {
+        forwardingService.deleteForwarding(forwardingId, (List<String>) request.getAttribute("projects"));
         return ResponseEntity.ok().build();
     }
 
diff --git a/src/main/java/com/aolda/itda/controller/log/LogController.java b/src/main/java/com/aolda/itda/controller/log/LogController.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d4bfcf7bedf91d5fc7d1fbca6f4d68e6a5e48e8
--- /dev/null
+++ b/src/main/java/com/aolda/itda/controller/log/LogController.java
@@ -0,0 +1,41 @@
+package com.aolda.itda.controller.log;
+
+import com.aolda.itda.service.log.LogService;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.web.PageableDefault;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/api")
+@RequiredArgsConstructor
+public class LogController {
+
+    private final LogService logService;
+
+    @GetMapping("/log")
+    public ResponseEntity<Object> view(@RequestParam Long logId, HttpServletRequest request) {
+        return ResponseEntity.ok(logService.getLog(logId, (List<String>) request.getAttribute("projects")));
+    }
+
+    @GetMapping("/logs")
+    public ResponseEntity<Object> lists(@RequestParam(required = false) String projectId
+                                        ,@RequestParam(required = false) String type
+                                        ,@RequestParam(required = false) String username
+                                        ,@RequestParam(required = false) String action
+                                        ,@RequestParam(defaultValue = "false") boolean isASC
+                                        ,@PageableDefault(size = 10) Pageable pageable
+                                        ,HttpServletRequest request) {
+        return ResponseEntity.ok(logService.getLogs(projectId, type, username, action, isASC, pageable,
+                (Map<String, String>) request.getAttribute("user")));
+    }
+
+}
diff --git a/src/main/java/com/aolda/itda/controller/routing/RoutingController.java b/src/main/java/com/aolda/itda/controller/routing/RoutingController.java
index aec9927a0aad984e7d43cf3a750d7ef3d46207a2..4b9d551ada34e56464d8b95e1577adff3f456d36 100644
--- a/src/main/java/com/aolda/itda/controller/routing/RoutingController.java
+++ b/src/main/java/com/aolda/itda/controller/routing/RoutingController.java
@@ -3,10 +3,13 @@ package com.aolda.itda.controller.routing;
 import com.aolda.itda.dto.forwarding.ForwardingDTO;
 import com.aolda.itda.dto.routing.RoutingDTO;
 import com.aolda.itda.service.routing.RoutingService;
+import jakarta.servlet.http.HttpServletRequest;
 import lombok.RequiredArgsConstructor;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.List;
+
 @RestController
 @RequestMapping("/api")
 @RequiredArgsConstructor
@@ -14,7 +17,7 @@ public class RoutingController {
 
     private final RoutingService routingService;
 
-    @PostMapping("/forwarding")
+    @PostMapping("/routing")
     public ResponseEntity<Object> create(@RequestParam String projectId,
                                          @RequestBody RoutingDTO dto) {
         routingService.createRouting(projectId, dto);
@@ -22,8 +25,9 @@ public class RoutingController {
     }
 
     @GetMapping("/routing")
-    public ResponseEntity<Object> view(@RequestParam Long routingId) {
-        return ResponseEntity.ok(routingService.getRouting(routingId));
+    public ResponseEntity<Object> view(@RequestParam Long routingId,
+                                       HttpServletRequest request) {
+        return ResponseEntity.ok(routingService.getRouting(routingId, (List<String>) request.getAttribute("projects")));
     }
 
     @GetMapping("/routings")
@@ -33,14 +37,16 @@ public class RoutingController {
 
     @PatchMapping("/routing")
     public ResponseEntity<Object> edit(@RequestParam Long routingId,
-                                       @RequestBody RoutingDTO dto) {
-        routingService.editRouting(routingId, dto);
+                                       @RequestBody RoutingDTO dto,
+                                       HttpServletRequest request) {
+        routingService.editRouting(routingId, dto, (List<String>) request.getAttribute("projects"));
         return ResponseEntity.ok().build();
     }
 
     @DeleteMapping("/routing")
-    public ResponseEntity<Object> delete(@RequestParam Long routingId) {
-        routingService.deleteRouting(routingId);
+    public ResponseEntity<Object> delete(@RequestParam Long routingId,
+                                         HttpServletRequest request) {
+        routingService.deleteRouting(routingId, (List<String>) request.getAttribute("projects"));
         return ResponseEntity.ok().build();
     }
 
diff --git a/src/main/java/com/aolda/itda/dto/PageResp.java b/src/main/java/com/aolda/itda/dto/PageResp.java
index 49a2a6cdbacdee106e68588dc7b22cb43bb70fa7..7079600bbabe8b47e3e4c57f5267e8b287c8a473 100644
--- a/src/main/java/com/aolda/itda/dto/PageResp.java
+++ b/src/main/java/com/aolda/itda/dto/PageResp.java
@@ -15,7 +15,7 @@ import java.util.List;
 @JsonInclude(JsonInclude.Include.NON_NULL)
 public class PageResp<T> {
     private Integer totalPages;
-    private Integer totalElements;
+    private Long totalElements;
     private Integer size;
     private List<T> contents;
     private Boolean first;
diff --git a/src/main/java/com/aolda/itda/dto/auth/IdAndNameDTO.java b/src/main/java/com/aolda/itda/dto/auth/IdAndNameDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..5918105381265b66446aa2d221657508e177fb58
--- /dev/null
+++ b/src/main/java/com/aolda/itda/dto/auth/IdAndNameDTO.java
@@ -0,0 +1,24 @@
+package com.aolda.itda.dto.auth;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.querydsl.core.annotations.QueryProjection;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@NoArgsConstructor
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class IdAndNameDTO {
+
+    private String id;
+    private String name;
+
+    @QueryProjection
+    public IdAndNameDTO(String id, String name) {
+        this.id = id;
+        this.name = name;
+    }
+}
diff --git a/src/main/java/com/aolda/itda/dto/auth/LoginResponseDTO.java b/src/main/java/com/aolda/itda/dto/auth/LoginResponseDTO.java
index 33ba32fd358f5ab1fffecbe0965cc8921a88bbb2..a647b05835b9614cf21b1b8340a31b256fade9bc 100644
--- a/src/main/java/com/aolda/itda/dto/auth/LoginResponseDTO.java
+++ b/src/main/java/com/aolda/itda/dto/auth/LoginResponseDTO.java
@@ -13,5 +13,5 @@ import java.util.List;
 @Builder
 public class LoginResponseDTO {
     private Boolean isAdmin;
-    private List<ProjectIdAndNameDTO> projects;
+    private List<IdAndNameDTO> projects;
 }
diff --git a/src/main/java/com/aolda/itda/dto/auth/ProjectIdAndNameDTO.java b/src/main/java/com/aolda/itda/dto/auth/ProjectIdAndNameDTO.java
deleted file mode 100644
index 1ca894d2bf9b9cd5f29244ac95e7c4950daec174..0000000000000000000000000000000000000000
--- a/src/main/java/com/aolda/itda/dto/auth/ProjectIdAndNameDTO.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.aolda.itda.dto.auth;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-
-@Getter
-@NoArgsConstructor
-@AllArgsConstructor
-@Builder
-public class ProjectIdAndNameDTO {
-
-    private String id;
-    private String name;
-}
diff --git a/src/main/java/com/aolda/itda/dto/log/LogDTO.java b/src/main/java/com/aolda/itda/dto/log/LogDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..589545518431c85d093ca695b3cb97778fb9bac0
--- /dev/null
+++ b/src/main/java/com/aolda/itda/dto/log/LogDTO.java
@@ -0,0 +1,38 @@
+package com.aolda.itda.dto.log;
+
+import com.aolda.itda.dto.auth.IdAndNameDTO;
+import com.aolda.itda.entity.log.Action;
+import com.aolda.itda.entity.log.ObjectType;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.querydsl.core.annotations.QueryProjection;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+@Data
+@NoArgsConstructor
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class LogDTO {
+    private Long id;
+    private IdAndNameDTO user;
+    private Action action;
+    private ObjectType type;
+    private Long objectId;
+    private String description;
+    private LocalDateTime createdAt;
+
+    @QueryProjection
+    public LogDTO(Long id, IdAndNameDTO user, Action action, ObjectType type, Long objectId, String description, LocalDateTime createdAt) {
+        this.id = id;
+        this.user = user;
+        this.action = action;
+        this.type = type;
+        this.objectId = objectId;
+        this.description = description;
+        this.createdAt = createdAt;
+    }
+}
diff --git a/src/main/java/com/aolda/itda/dto/routing/RoutingDTO.java b/src/main/java/com/aolda/itda/dto/routing/RoutingDTO.java
index e95ab70e8763ab7c3db0a5e7d884d6e50662b1bf..6bc48d87f455151d743711bd40037496257fb940 100644
--- a/src/main/java/com/aolda/itda/dto/routing/RoutingDTO.java
+++ b/src/main/java/com/aolda/itda/dto/routing/RoutingDTO.java
@@ -25,7 +25,7 @@ public class RoutingDTO {
     @NotBlank
     private String port;
     private Long id;
-    @NotBlank
+    @NotNull
     private Long certificateId;
 
     private LocalDateTime createdAt;
diff --git a/src/main/java/com/aolda/itda/entity/BaseTimeEntity.java b/src/main/java/com/aolda/itda/entity/BaseTimeEntity.java
index 4460eb7b0c8c1401e10dcc56a34a09e81beca59a..6cfa1fde46f85bae5cf6c3ae7b2e543002db0ad9 100644
--- a/src/main/java/com/aolda/itda/entity/BaseTimeEntity.java
+++ b/src/main/java/com/aolda/itda/entity/BaseTimeEntity.java
@@ -1,5 +1,6 @@
 package com.aolda.itda.entity;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import jakarta.persistence.Column;
 import jakarta.persistence.EntityListeners;
 import jakarta.persistence.MappedSuperclass;
@@ -17,10 +18,12 @@ public abstract class BaseTimeEntity {
 
     @CreatedDate
     @Column(updatable = false)
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
     private LocalDateTime createdAt;
 
     @LastModifiedDate
     @Column(name = "updated_at")
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
     private LocalDateTime updatedAt;
 
 }
diff --git a/src/main/java/com/aolda/itda/entity/certificate/Certificate.java b/src/main/java/com/aolda/itda/entity/certificate/Certificate.java
index 188f05e106121abe6f26b70fde078e0bd8d50662..a23cf858c8926a19b36a1b81df45b3b0bfd033f3 100644
--- a/src/main/java/com/aolda/itda/entity/certificate/Certificate.java
+++ b/src/main/java/com/aolda/itda/entity/certificate/Certificate.java
@@ -23,7 +23,7 @@ public class Certificate extends BaseTimeEntity {
     @Column(nullable = false)
     private Long certificateId;
 
-    @OneToOne
+    @ManyToOne
     @JoinColumn(nullable = false, name = "user_id")
     private User user;
 
diff --git a/src/main/java/com/aolda/itda/entity/forwarding/Forwarding.java b/src/main/java/com/aolda/itda/entity/forwarding/Forwarding.java
index b0c8d34715c26ce8334e6037ea97c65329761c72..0e5e50559860fbebf6cc5378fa91bd6fcefa00fa 100644
--- a/src/main/java/com/aolda/itda/entity/forwarding/Forwarding.java
+++ b/src/main/java/com/aolda/itda/entity/forwarding/Forwarding.java
@@ -4,10 +4,7 @@ import com.aolda.itda.dto.forwarding.ForwardingDTO;
 import com.aolda.itda.entity.BaseTimeEntity;
 import com.aolda.itda.entity.user.User;
 import jakarta.persistence.*;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
+import lombok.*;
 
 @Entity
 @Table(name = "forwarding")
@@ -15,6 +12,7 @@ import lombok.NoArgsConstructor;
 @Builder
 @NoArgsConstructor
 @AllArgsConstructor
+@ToString
 public class Forwarding extends BaseTimeEntity {
 
     @Id
@@ -22,10 +20,6 @@ public class Forwarding extends BaseTimeEntity {
     @Column(nullable = false)
     private Long forwardingId;
 
-    @OneToOne
-    @JoinColumn(name = "user_id")
-    private User user;
-
     private String projectId;
 
     private String serverIp;
@@ -40,6 +34,17 @@ public class Forwarding extends BaseTimeEntity {
 
     private String name;
 
+    public Forwarding(Forwarding forwarding) {
+        this.forwardingId = forwarding.getForwardingId();
+        this.projectId = forwarding.getProjectId();
+        this.serverIp = forwarding.getServerIp();
+        this.serverPort = forwarding.getServerPort();
+        this.instanceIp = forwarding.getInstanceIp();
+        this.instancePort = forwarding.getInstancePort();
+        this.isDeleted = forwarding.getIsDeleted();
+        this.name = forwarding.getName();
+    }
+
     public ForwardingDTO toForwardingDTO() {
         return ForwardingDTO.builder()
                 .id(forwardingId)
diff --git a/src/main/java/com/aolda/itda/entity/log/Log.java b/src/main/java/com/aolda/itda/entity/log/Log.java
index fa78a6677f3cbb66322056a83dfd2a404eb5435c..9832ab291bdd2b8aaf5a8b6ea2d6823e71a55df7 100644
--- a/src/main/java/com/aolda/itda/entity/log/Log.java
+++ b/src/main/java/com/aolda/itda/entity/log/Log.java
@@ -1,5 +1,7 @@
 package com.aolda.itda.entity.log;
 
+import com.aolda.itda.dto.auth.IdAndNameDTO;
+import com.aolda.itda.dto.log.LogDTO;
 import com.aolda.itda.entity.BaseTimeEntity;
 import com.aolda.itda.entity.user.User;
 import jakarta.persistence.*;
@@ -21,7 +23,7 @@ public class Log extends BaseTimeEntity {
     @Column(nullable = false)
     private Long logId;
 
-    @OneToOne
+    @ManyToOne
     @JoinColumn(name = "user_id", nullable = false)
     private User user;
 
@@ -37,4 +39,16 @@ public class Log extends BaseTimeEntity {
 
     private String description;
 
+    public LogDTO toLogDTO() {
+        return LogDTO.builder()
+                .id(logId)
+                .user(IdAndNameDTO.builder().id(user.getKeystoneId()).name(user.getKeystoneUsername()).build())
+                .action(action)
+                .type(objectType)
+                .objectId(objectId)
+                .description(description)
+                .createdAt(getCreatedAt())
+                .build();
+    }
+
 }
diff --git a/src/main/java/com/aolda/itda/entity/routing/Routing.java b/src/main/java/com/aolda/itda/entity/routing/Routing.java
index be03dcd3edd27000c8c00aea2437ac65da1c72d5..de13d82d149e0ec8c6acd60c162b9e980eb1bc91 100644
--- a/src/main/java/com/aolda/itda/entity/routing/Routing.java
+++ b/src/main/java/com/aolda/itda/entity/routing/Routing.java
@@ -24,12 +24,8 @@ public class Routing extends BaseTimeEntity {
     @Column(nullable = false)
     private Long routingId;
 
-    @OneToOne
-    @JoinColumn(name = "user_id", nullable = false)
-    private User user;
-
-    @OneToOne
-    @JoinColumn(name = "certificate_id", nullable = false)
+    @ManyToOne
+    @JoinColumn(name = "certificate_id")
     private Certificate certificate;
 
     private String projectId;
diff --git a/src/main/java/com/aolda/itda/exception/ErrorCode.java b/src/main/java/com/aolda/itda/exception/ErrorCode.java
index 321bdaddd8b6eb5a3f523e8e56b5d738e3105319..3e4b0be8af87fa6ad85462e6a86fb52d6c295b2d 100644
--- a/src/main/java/com/aolda/itda/exception/ErrorCode.java
+++ b/src/main/java/com/aolda/itda/exception/ErrorCode.java
@@ -10,6 +10,8 @@ public enum ErrorCode {
 
     // User
     INVALID_USER_INFO(HttpStatus.BAD_REQUEST, "잘못된 회원 정보입니다"),
+    NOT_FOUND_USER(HttpStatus.BAD_REQUEST, "존재하지 않는 사용자입니다"),
+    UNAUTHORIZED_USER(HttpStatus.BAD_REQUEST, "권한이 없는 사용자입니다"),
 
     // Token
     INVALID_TOKEN(HttpStatus.BAD_REQUEST, "잘못된 토큰입니다"),
@@ -19,6 +21,9 @@ public enum ErrorCode {
 
     // Routing
     NOT_FOUND_ROUTING(HttpStatus.BAD_REQUEST, "라우팅 파일이 존재하지 않습니다"),
+    
+    // Routing
+    NOT_FOUND_LOG(HttpStatus.BAD_REQUEST, "로그가 존재하지 않습니다"),
 
     // Certificate
     NOT_FOUND_CERTIFICATE(HttpStatus.BAD_REQUEST, "SSL 인증서가 존재하지 않습니다"),
diff --git a/src/main/java/com/aolda/itda/repository/log/LogQueryDSL.java b/src/main/java/com/aolda/itda/repository/log/LogQueryDSL.java
new file mode 100644
index 0000000000000000000000000000000000000000..ceba4b235799104d9b590a3d4c47aed6a92e11bc
--- /dev/null
+++ b/src/main/java/com/aolda/itda/repository/log/LogQueryDSL.java
@@ -0,0 +1,102 @@
+package com.aolda.itda.repository.log;
+
+import com.aolda.itda.dto.PageResp;
+import com.aolda.itda.dto.auth.QIdAndNameDTO;
+import com.aolda.itda.dto.log.LogDTO;
+import com.aolda.itda.dto.log.QLogDTO;
+import com.aolda.itda.entity.log.Action;
+import com.aolda.itda.entity.log.ObjectType;
+import com.querydsl.core.BooleanBuilder;
+import com.querydsl.jpa.impl.JPAQuery;
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.support.PageableExecutionUtils;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+import static com.aolda.itda.entity.log.QLog.*;
+import static com.aolda.itda.entity.user.QUser.*;
+
+@Repository
+@RequiredArgsConstructor
+public class LogQueryDSL {
+
+    private final JPAQueryFactory jpaQueryFactory;
+
+    /* log 목록 반환 */
+    public PageResp<LogDTO> getLogs(String projectId, String type,
+                                    String username, String action, Boolean isASC, Pageable pageable) {
+
+        List<LogDTO> content = jpaQueryFactory
+                .select(new QLogDTO(
+                        log.logId,
+                        new QIdAndNameDTO(user.keystoneId, user.keystoneUsername),
+                        log.action,
+                        log.objectType,
+                        log.objectId,
+                        log.description,
+                        log.createdAt
+                )).from(log)
+                .join(log.user, user).on(log.user.eq(user))
+                .where(getFilter(projectId, type, username, action))
+                .orderBy(isASC ? log.logId.asc() : log.logId.desc())
+                .offset(pageable.getOffset())
+                .limit(pageable.getPageSize())
+                .fetch();
+
+        JPAQuery<Long> cnt = jpaQueryFactory
+                .select(log.count())
+                .from(log)
+                .where(getFilter(projectId, type, username, action));
+
+        Page<LogDTO> page = PageableExecutionUtils.getPage(content, pageable, cnt::fetchOne);
+
+        return PageResp.<LogDTO>builder()
+                .contents(page.getContent())
+                .first(page.isFirst())
+                .last(page.isLast())
+                .size(page.getSize())
+                .totalPages(page.getTotalPages())
+                .totalElements(page.getTotalElements())
+                .build();
+    }
+
+    /* Where 필터 */
+    private BooleanBuilder getFilter(String projectId, String type,
+                                     String username, String action) {
+        BooleanBuilder builder = new BooleanBuilder();
+
+        /* 프로젝트 조건 */
+        if (projectId != null) {
+            builder.and(log.projectId.eq(projectId));
+        }
+
+        /* 오브젝트 타입 조건 */
+        if (type != null) {
+            switch (type) {
+                case "certificate" -> builder.and(log.objectType.eq(ObjectType.CERTIFICATE));
+                case "forwarding" -> builder.and(log.objectType.eq(ObjectType.FORWARDING));
+                case "routing" -> builder.and(log.objectType.eq(ObjectType.ROUTING));
+            }
+        }
+
+
+        /* 사용자 ID 조건 */
+        if (username != null) {
+            builder.and(log.user.keystoneUsername.eq(username));
+        }
+
+        /* CUD 조건 */
+        if (action != null) {
+            switch (action) {
+                case "create" -> builder.and(log.action.eq(Action.CREATE));
+                case "update" -> builder.and(log.action.eq(Action.UPDATE));
+                case "delete" -> builder.and(log.action.eq(Action.DELETE));
+            }
+        }
+        return builder;
+    }
+}
diff --git a/src/main/java/com/aolda/itda/repository/log/LogRepository.java b/src/main/java/com/aolda/itda/repository/log/LogRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..de0a769f6b1b206f5d350aae620fa997f7763006
--- /dev/null
+++ b/src/main/java/com/aolda/itda/repository/log/LogRepository.java
@@ -0,0 +1,10 @@
+package com.aolda.itda.repository.log;
+
+import com.aolda.itda.entity.log.Log;
+import com.aolda.itda.entity.routing.Routing;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface LogRepository extends JpaRepository<Log, Long> {
+}
diff --git a/src/main/java/com/aolda/itda/repository/user/UserRepository.java b/src/main/java/com/aolda/itda/repository/user/UserRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..44cae688e4032b6caec7482c6c6f7e3c038736e2
--- /dev/null
+++ b/src/main/java/com/aolda/itda/repository/user/UserRepository.java
@@ -0,0 +1,11 @@
+package com.aolda.itda.repository.user;
+
+import com.aolda.itda.entity.user.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface UserRepository extends JpaRepository<User, Long> {
+    Optional<User> findByKeystoneId(String keystoneId);
+    Optional<User> findByKeystoneUsername(String keystoneUsername);
+}
diff --git a/src/main/java/com/aolda/itda/service/AuthService.java b/src/main/java/com/aolda/itda/service/AuthService.java
index cc523fa856bbb7101e995e049bb7b3bdfb196127..80c53d38568e4cd09d752bf2b8cbb11e788af23b 100644
--- a/src/main/java/com/aolda/itda/service/AuthService.java
+++ b/src/main/java/com/aolda/itda/service/AuthService.java
@@ -2,9 +2,11 @@ package com.aolda.itda.service;
 
 import com.aolda.itda.dto.auth.LoginRequestDTO;
 import com.aolda.itda.dto.auth.LoginResponseDTO;
-import com.aolda.itda.dto.auth.ProjectIdAndNameDTO;
+import com.aolda.itda.dto.auth.IdAndNameDTO;
+import com.aolda.itda.entity.user.User;
 import com.aolda.itda.exception.CustomException;
 import com.aolda.itda.exception.ErrorCode;
+import com.aolda.itda.repository.user.UserRepository;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -31,6 +33,7 @@ public class AuthService {
     private String adminPassword;
     private final RestTemplate restTemplate = new RestTemplate();
     private final ObjectMapper objectMapper = new ObjectMapper();
+    private final UserRepository userRepository;
 
     // 사용자 로그인 후 토큰 발행 및 Role 반환
     public LoginResponseDTO userLogin(HttpServletResponse response, LoginRequestDTO loginRequestDTO) throws JsonProcessingException {
@@ -44,6 +47,13 @@ public class AuthService {
             throw new CustomException(ErrorCode.INVALID_USER_INFO);
         }
 
+
+        User entity = userRepository.findByKeystoneUsername(userId).orElse(null);
+        if (entity == null) {
+            userRepository.save(User.builder().keystoneId(validateTokenAndGetUserId(token)).
+                    keystoneUsername(loginRequestDTO.getId()).build());
+        }
+
         response.addHeader("X-Subject-Token", systemToken != null ? systemToken : token);
         return LoginResponseDTO.builder()
                 .isAdmin(systemToken != null)
@@ -239,7 +249,7 @@ public class AuthService {
     }
 
     // 특정 사용자의 참여 프로젝트 반환
-    private List<ProjectIdAndNameDTO> getProjectsWithUser(Map<String, String> user) throws JsonProcessingException {
+    public List<IdAndNameDTO> getProjectsWithUser(Map<String, String> user) throws JsonProcessingException {
         String userId = user.get("id");
         String token = user.get("token");
         if (userId == null || token == null) {
@@ -257,12 +267,12 @@ public class AuthService {
         JsonNode node = objectMapper.readTree(res.getBody());
         ArrayNode arrayNode = (ArrayNode) node.get("projects");
 
-        List<ProjectIdAndNameDTO> lists = new ArrayList<>();
+        List<IdAndNameDTO> lists = new ArrayList<>();
 
         for (JsonNode assignment : arrayNode) {
             String projectId = assignment.path("id").asText();
             String projectName = assignment.path("name").asText();
-            lists.add(new ProjectIdAndNameDTO(projectId, projectName));
+            lists.add(new IdAndNameDTO(projectId, projectName));
         }
         return lists;
     }
@@ -283,7 +293,13 @@ public class AuthService {
 
     }
 
-    private Boolean isAdmin(Map<String, String> user) throws JsonProcessingException {
+    public void validateProjectAuth(List<String> projects, String projectId) {
+        if (projects != null && !projects.contains(projectId)) {
+            throw new CustomException(ErrorCode.UNAUTHORIZED_USER);
+        }
+    }
+
+    public Boolean isAdmin(Map<String, String> user) throws JsonProcessingException {
         String url = keystone + "/role_assignments?user.id=" + user.get("id") + "&scope.system&include_names";
         HttpHeaders headers = new HttpHeaders();
         headers.set("X-Auth-Token", user.get("token"));
diff --git a/src/main/java/com/aolda/itda/service/forwarding/ForwardingService.java b/src/main/java/com/aolda/itda/service/forwarding/ForwardingService.java
index 9ec934398f5635dbb05e868888506f2140757f1c..85c1ec3eb5450c7adae76f06f22724397f1e09f1 100644
--- a/src/main/java/com/aolda/itda/service/forwarding/ForwardingService.java
+++ b/src/main/java/com/aolda/itda/service/forwarding/ForwardingService.java
@@ -6,20 +6,16 @@ import com.aolda.itda.entity.forwarding.Forwarding;
 import com.aolda.itda.exception.CustomException;
 import com.aolda.itda.exception.ErrorCode;
 import com.aolda.itda.repository.forwarding.ForwardingRepository;
+import com.aolda.itda.service.AuthService;
 import com.aolda.itda.template.ForwardingTemplate;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import jakarta.validation.ConstraintViolation;
 import jakarta.validation.Validation;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.client.HttpClientErrorException;
 import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.RestClientException;
 import org.springframework.web.client.RestTemplate;
 
 import java.io.BufferedWriter;
@@ -30,7 +26,7 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
-import java.util.Map;
+import java.util.List;
 
 @Service
 @Transactional
@@ -42,12 +38,17 @@ public class ForwardingService {
     private String serverBaseIp;
     private final ForwardingTemplate forwardingTemplate;
     private final ForwardingRepository forwardingRepository;
+    private final AuthService authService;
     private final RestTemplate restTemplate = new RestTemplate();
 
     /* 포트포워딩 정보 조회 */
-    public ForwardingDTO getForwarding(Long forwardingId) {
+    public ForwardingDTO getForwarding(Long forwardingId, List<String> projects) {
         Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(forwardingId, false)
                 .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_FORWARDING));
+
+        /* 프로젝트 권한 검증 */
+        authService.validateProjectAuth(projects, forwarding.getProjectId());
+
         return forwarding.toForwardingDTO();
     }
 
@@ -62,7 +63,7 @@ public class ForwardingService {
     }
 
     /* 포트포워딩 생성 */
-    public void createForwarding(String projectId, ForwardingDTO dto) {
+    public ForwardingDTO createForwarding(String projectId, ForwardingDTO dto) {
 
         /* 입력 DTO 검증 */
         validateDTO(dto);
@@ -154,14 +155,16 @@ public class ForwardingService {
             }
             throw new CustomException(ErrorCode.FAIL_NGINX_CONF_RELOAD);
         }
-
+        return forwarding.toForwardingDTO();
     }
 
     /* 포트포워딩 정보 수정 */
-    public void editForwarding(Long forwardingId, ForwardingDTO dto) {
+    public void editForwarding(Long forwardingId, ForwardingDTO dto, List<String> projects) {
         Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(forwardingId, false)
                 .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_FORWARDING));
 
+        /* 프로젝트 권한 검증 */
+        authService.validateProjectAuth(projects, forwarding.getProjectId());
 
         /* 중복 검증 */
         if (dto.getServerPort() != null && forwardingRepository.existsByServerPortAndIsDeleted(dto.getServerPort(), false)) {
@@ -270,10 +273,13 @@ public class ForwardingService {
     }
 
     /* 포트포워딩 삭제 (소프트) */
-    public void deleteForwarding(Long forwardingId) {
+    public void deleteForwarding(Long forwardingId, List<String> projects) {
         Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(forwardingId, false)
                 .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_FORWARDING));
 
+        /* 프로젝트 권한 검증 */
+        authService.validateProjectAuth(projects, forwarding.getProjectId());
+
         /* 파일 삭제 */
         String confPath = "/data/nginx/stream/" + forwarding.getForwardingId() + ".conf";
         String deletePath = confPath + ".deleted";
diff --git a/src/main/java/com/aolda/itda/service/log/LogService.java b/src/main/java/com/aolda/itda/service/log/LogService.java
new file mode 100644
index 0000000000000000000000000000000000000000..b33cc2e4a1e923ed046bea7aaff6ddc18c345c53
--- /dev/null
+++ b/src/main/java/com/aolda/itda/service/log/LogService.java
@@ -0,0 +1,57 @@
+package com.aolda.itda.service.log;
+
+import com.aolda.itda.dto.PageResp;
+import com.aolda.itda.dto.log.LogDTO;
+import com.aolda.itda.entity.log.Log;
+import com.aolda.itda.exception.CustomException;
+import com.aolda.itda.exception.ErrorCode;
+import com.aolda.itda.repository.log.LogRepository;
+import com.aolda.itda.repository.log.LogQueryDSL;
+import com.aolda.itda.service.AuthService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Map;
+
+@Service
+@Transactional
+@RequiredArgsConstructor
+@Slf4j
+public class LogService {
+
+    private final LogRepository logRepository;
+    private final LogQueryDSL logQueryDSL;
+    private final AuthService authService;
+
+    /* CUD 로그 조회 */
+    public LogDTO getLog(Long logId, List<String> projects) {
+        Log log = logRepository.findById(logId)
+                .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_LOG));
+
+        /* 프로젝트 권한 검증 */
+        authService.validateProjectAuth(projects, log.getProjectId());
+
+        return log.toLogDTO();
+    }
+
+    /* CUD 로그 목록 조회 */
+    public PageResp<LogDTO> getLogs(String projectId, String type, String username, String action, Boolean isASC,
+                                    Pageable pageable, Map<String, String> user) {
+
+        if (projectId == null) {
+            try {
+                if(!authService.isAdmin(user)) throw new CustomException(ErrorCode.UNAUTHORIZED_USER);
+            }
+            catch (Exception e) {
+                throw new CustomException(ErrorCode.UNAUTHORIZED_USER);
+            }
+        }
+
+        return logQueryDSL.getLogs(projectId, type, username, action, isASC, pageable);
+    }
+
+}
diff --git a/src/main/java/com/aolda/itda/service/routing/RoutingService.java b/src/main/java/com/aolda/itda/service/routing/RoutingService.java
index 9cfad7d4ec75d158fce65ced051f8036749ef5b2..7b30c9127796b6dda07d65207a0bc37abbdb9b92 100644
--- a/src/main/java/com/aolda/itda/service/routing/RoutingService.java
+++ b/src/main/java/com/aolda/itda/service/routing/RoutingService.java
@@ -8,6 +8,7 @@ import com.aolda.itda.exception.CustomException;
 import com.aolda.itda.exception.ErrorCode;
 import com.aolda.itda.repository.certificate.CertificateRepository;
 import com.aolda.itda.repository.routing.RoutingRepository;
+import com.aolda.itda.service.AuthService;
 import com.aolda.itda.template.RoutingTemplate;
 import jakarta.validation.ConstraintViolation;
 import jakarta.validation.Validation;
@@ -26,6 +27,7 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
+import java.util.List;
 
 @Service
 @Transactional
@@ -35,20 +37,23 @@ public class RoutingService {
 
     private final RoutingRepository routingRepository;
     private final CertificateRepository certificateRepository;
+    private final AuthService authService;
     private final RoutingTemplate routingTemplate;
     private final RestTemplate restTemplate = new RestTemplate();
 
     /* Routing 조회 */
-    public RoutingDTO getRouting(Long routingId) {
-        // project id 확인 필요
+    public RoutingDTO getRouting(Long routingId, List<String> projects) {
         Routing routing = routingRepository.findByRoutingIdAndIsDeleted(routingId, false)
                 .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_ROUTING));
+
+        /* 프로젝트 권한 검증 */
+        authService.validateProjectAuth(projects, routing.getProjectId());
+
         return routing.toRoutingDTO();
     }
 
     /* Routing 목록 조회 */
     public PageResp<RoutingDTO> getRoutings(String projectId) {
-        // project id 확인 필요
         return PageResp.<RoutingDTO>builder()
                 .contents(routingRepository.findByProjectIdAndIsDeleted(projectId, false)
                         .stream()
@@ -57,7 +62,7 @@ public class RoutingService {
     }
 
     /* Routing 생성 */
-    public void createRouting(String projectId, RoutingDTO dto) {
+    public RoutingDTO createRouting(String projectId, RoutingDTO dto) {
         /* 입력 DTO 검증 */
         validateDTO(dto);
 
@@ -151,15 +156,16 @@ public class RoutingService {
             throw new CustomException(ErrorCode.FAIL_NGINX_CONF_RELOAD);
         }
 
+        return routing.toRoutingDTO();
     }
 
     /* Routing 수정 */
-    public void editRouting(Long routingId, RoutingDTO dto) {
+    public void editRouting(Long routingId, RoutingDTO dto, List<String> projects) {
         Routing routing = routingRepository.findByRoutingIdAndIsDeleted(routingId, false)
                 .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_ROUTING));
 
-        /* 입력 DTO 검증 */
-        validateDTO(dto);
+        /* 프로젝트 권한 검증 */
+        authService.validateProjectAuth(projects, routing.getProjectId());
 
         /* 중복 검증 */
         if (dto.getDomain() != null && routingRepository.existsByDomainAndIsDeleted(dto.getDomain(), false)) {
@@ -173,7 +179,9 @@ public class RoutingService {
 
         /* 파일 수정 */
         routing.edit(dto, certificate);
-        String content = routingTemplate.getRouting(routing.toRoutingDTO(), certificate == null ? null : certificate.formatDomain());
+        RoutingDTO tmp = routing.toRoutingDTO();
+        if (tmp.getCertificateId() == null) tmp.setCertificateId( (long) -1);
+        String content = routingTemplate.getRouting(tmp, certificate == null ? null : certificate.formatDomain());
         String confPath = "/data/nginx/proxy_host/" + routing.getRoutingId() + ".conf";
         File file = new File(confPath);
         if (!file.exists()) {
@@ -253,10 +261,13 @@ public class RoutingService {
     }
 
     /* Routing 삭제 */
-    public void deleteRouting(Long routingId) {
+    public void deleteRouting(Long routingId, List<String> projects) {
         Routing routing = routingRepository.findByRoutingIdAndIsDeleted(routingId, false)
                 .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_ROUTING));
 
+        /* 프로젝트 권한 검증 */
+        authService.validateProjectAuth(projects, routing.getProjectId());
+
         /* 파일 삭제 */
         String confPath = "/data/nginx/proxy_host/" + routing.getRoutingId() + ".conf";
         String deletePath = confPath + ".deleted";