diff --git a/src/main/java/com/aolda/itda/controller/certificate/CertificateController.java b/src/main/java/com/aolda/itda/controller/certificate/CertificateController.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6384c923076c6144efc770aa77a6e25a533cbec
--- /dev/null
+++ b/src/main/java/com/aolda/itda/controller/certificate/CertificateController.java
@@ -0,0 +1,93 @@
+package com.aolda.itda.controller.certificate;
+
+import com.aolda.itda.dto.certificate.CertificateDTO;
+import com.aolda.itda.service.certificate.CertificateService;
+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
+public class CertificateController {
+
+    private final CertificateService certificateService;
+
+    /**
+     * 인증서 생성
+     * POST /api/certificate?projectId=xxx
+     * Body: CertificateDTO
+     */
+    @PostMapping("/certificate")
+    public ResponseEntity<Object> create(@RequestParam String projectId,
+                                         @RequestBody CertificateDTO dto,
+                                         HttpServletRequest request) {
+        certificateService.createCertificate(
+                projectId,
+                dto,
+                (List<String>) request.getAttribute("projects") // Forwarding과 동일하게
+        );
+        return ResponseEntity.ok().build();
+    }
+
+    /**
+     * 인증서 단건 조회
+     * GET /api/certificate?certificateId=xxx
+     */
+    @GetMapping("/certificate")
+    public ResponseEntity<Object> view(@RequestParam Long certificateId,
+                                       HttpServletRequest request) {
+        return ResponseEntity.ok(
+                certificateService.getCertificate(
+                        certificateId,
+                        (List<String>) request.getAttribute("projects")
+                )
+        );
+    }
+
+    /**
+     * 인증서 목록 조회
+     * GET /api/certificates?projectId=xxx
+     */
+    @GetMapping("/certificates")
+    public ResponseEntity<Object> lists(@RequestParam String projectId) {
+        return ResponseEntity.ok(
+                certificateService.getCertificates(projectId)
+        );
+    }
+
+    /**
+     * 인증서 수정
+     * PATCH /api/certificate?certificateId=xxx
+     * Body: CertificateDTO
+     */
+    @PatchMapping("/certificate")
+    public ResponseEntity<Object> edit(@RequestParam Long certificateId,
+                                       @RequestBody CertificateDTO dto,
+                                       HttpServletRequest request) {
+        certificateService.editCertificate(
+                certificateId,
+                dto,
+                (List<String>) request.getAttribute("projects")
+        );
+        return ResponseEntity.ok().build();
+    }
+
+    /**
+     * 인증서 삭제
+     * DELETE /api/certificate?certificateId=xxx
+     */
+    @DeleteMapping("/certificate")
+    public ResponseEntity<Object> delete(@RequestParam Long certificateId,
+                                         HttpServletRequest request) {
+        certificateService.deleteCertificate(
+                certificateId,
+                (List<String>) request.getAttribute("projects")
+        );
+        return ResponseEntity.ok().build();
+    }
+
+}
diff --git a/src/main/java/com/aolda/itda/dto/certificate/CertificateDTO.java b/src/main/java/com/aolda/itda/dto/certificate/CertificateDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..35aad948a3c16fae5d8556ed46f9e57a192b19dc
--- /dev/null
+++ b/src/main/java/com/aolda/itda/dto/certificate/CertificateDTO.java
@@ -0,0 +1,21 @@
+package com.aolda.itda.dto.certificate;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class CertificateDTO {
+
+    private Long certificateId;
+    private String projectId;
+    private String domain;
+    private LocalDateTime expiredAt;   // 필요 시
+    private Boolean isDeleted;
+    private String description;        // 추가 설명
+}
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 85b1f29b492b15fa7e213d6f94ee8f683d55c61e..469ea6aefadf46dd1ce2789ca7aea720427a42ec 100644
--- a/src/main/java/com/aolda/itda/entity/certificate/Certificate.java
+++ b/src/main/java/com/aolda/itda/entity/certificate/Certificate.java
@@ -49,4 +49,13 @@ public class Certificate extends BaseTimeEntity {
     public String formatDomain() {
         return domain == null ? null : domain.replace("*", "_");
     }
+
+    public void setIsDeleted(boolean b) {
+    }
+
+    public void setDomain(String domain) {
+    }
+
+    public void setDescription(String description) {
+    }
 }
diff --git a/src/main/java/com/aolda/itda/repository/certificate/CertificateRepository.java b/src/main/java/com/aolda/itda/repository/certificate/CertificateRepository.java
index 392c90b0aa31f7b445067f7db1ef490a379abf5d..1ce5c1fa17c006138df409444d9476bdd8a9b3fa 100644
--- a/src/main/java/com/aolda/itda/repository/certificate/CertificateRepository.java
+++ b/src/main/java/com/aolda/itda/repository/certificate/CertificateRepository.java
@@ -1,7 +1,18 @@
 package com.aolda.itda.repository.certificate;
 
 import com.aolda.itda.entity.certificate.Certificate;
+import com.aolda.itda.entity.forwarding.Forwarding;
 import org.springframework.data.jpa.repository.JpaRepository;
 
+import java.util.List;
+import java.util.Optional;
+
 public interface CertificateRepository extends JpaRepository<Certificate, Long> {
+
+    // 단건 조회 (Soft Delete 고려)
+    Optional<Certificate> findByCertificateIdAndIsDeleted(Long certificateId, Boolean isDeleted);
+
+    // 프로젝트별 목록 조회 (Soft Delete 고려)
+    List<Certificate> findByProjectIdAndIsDeleted(String projectId, Boolean isDeleted);
+
 }
diff --git a/src/main/java/com/aolda/itda/service/certificate/CertificateService.java b/src/main/java/com/aolda/itda/service/certificate/CertificateService.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c0dbaf824b7e7f5f71fb7eb4ef421c3e8bd771d
--- /dev/null
+++ b/src/main/java/com/aolda/itda/service/certificate/CertificateService.java
@@ -0,0 +1,137 @@
+package com.aolda.itda.service.certificate;
+
+import com.aolda.itda.dto.PageResp;
+import com.aolda.itda.dto.certificate.CertificateDTO;
+import com.aolda.itda.entity.certificate.Certificate;
+import com.aolda.itda.exception.CustomException;
+import com.aolda.itda.exception.ErrorCode;
+import com.aolda.itda.repository.certificate.CertificateRepository;
+import com.aolda.itda.service.AuthService;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.Validation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Service
+@Transactional
+@RequiredArgsConstructor
+@Slf4j
+public class CertificateService {
+
+    private final CertificateRepository certificateRepository;
+    private final AuthService authService;
+
+    /* 인증서 하나 조회 */
+    public CertificateDTO getCertificate(Long certificateId, List<String> projects) {
+        Certificate certificate = certificateRepository
+                .findByCertificateIdAndIsDeleted(certificateId, false)
+                .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_FORWARDING));
+        // 여기서는 ErrorCode.NOT_FOUND_CERTIFICATE 등 새로운 코드로 교체 가능
+
+        // 프로젝트 권한 검증
+        authService.validateProjectAuth(projects, certificate.getProjectId());
+
+        return toDTO(certificate);
+    }
+
+    /* 인증서 목록 조회 */
+    public PageResp<CertificateDTO> getCertificates(String projectId) {
+        List<CertificateDTO> list = certificateRepository
+                .findByProjectIdAndIsDeleted(projectId, false)
+                .stream()
+                .map(this::toDTO)
+                .toList();
+
+        return PageResp.<CertificateDTO>builder()
+                .contents(list)
+                .build();
+    }
+
+    /* 인증서 생성 */
+    public CertificateDTO createCertificate(String projectId, CertificateDTO dto, List<String> projects) {
+        // 프로젝트 권한 검증
+        authService.validateProjectAuth(projects, projectId);
+
+        // DTO 유효성 검사
+        validateDTO(dto);
+
+        Certificate certificate = Certificate.builder()
+                .projectId(projectId)
+                .domain(dto.getDomain())
+                .description(dto.getDescription())
+                .isDeleted(false)
+                .build();
+
+        certificateRepository.save(certificate);
+
+        // 생성 로직 (certbot 호출 등) 필요 시 추가
+
+        return toDTO(certificate);
+    }
+
+    /* 인증서 수정  */
+    public CertificateDTO editCertificate(Long certificateId, CertificateDTO dto, List<String> projects) {
+        Certificate certificate = certificateRepository
+                .findByCertificateIdAndIsDeleted(certificateId, false)
+                .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_FORWARDING));
+
+        // 프로젝트 권한 검증
+        authService.validateProjectAuth(projects, certificate.getProjectId());
+
+        // 필요한 필드만 수정
+        if (dto.getDomain() != null) {
+            certificate.setDomain(dto.getDomain());
+        }
+        if (dto.getDescription() != null) {
+            certificate.setDescription(dto.getDescription());
+        }
+        // 기타 수정할 필드가 있다면 추가
+
+        // DB 저장
+        certificateRepository.save(certificate);
+
+        // 수정 로직(certbot 재발급 등) 필요 시 추가
+
+        return toDTO(certificate);
+    }
+
+    /* 인증서 삭제 (soft delete) */
+    public void deleteCertificate(Long certificateId, List<String> projects) {
+        Certificate certificate = certificateRepository
+                .findByCertificateIdAndIsDeleted(certificateId, false)
+                .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_FORWARDING));
+
+        // 권한 검증
+        authService.validateProjectAuth(projects, certificate.getProjectId());
+
+        // soft delete
+        certificate.setIsDeleted(true);
+        certificateRepository.save(certificate);
+
+        // (추가) 파일 제거 / certbot revoke 등 로직 필요 시
+    }
+
+    /* DTO 유효성 검사 */
+    private void validateDTO(CertificateDTO dto) {
+        for (ConstraintViolation<CertificateDTO> violation
+                : Validation.buildDefaultValidatorFactory().getValidator().validate(dto)) {
+            throw new CustomException(ErrorCode.INVALID_CONF_INPUT, violation.getMessage());
+        }
+    }
+
+    /* Entity -> DTO 변환 */
+    private CertificateDTO toDTO(Certificate certificate) {
+        return CertificateDTO.builder()
+                .certificateId(certificate.getCertificateId())
+                .projectId(certificate.getProjectId())
+                .domain(certificate.getDomain())
+                .description(certificate.getDescription())
+                .isDeleted(certificate.getIsDeleted())
+                .expiredAt(certificate.getExpiredAt())
+                .build();
+    }
+}