diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/configs/SecurityConfig.kt b/src/main/kotlin/kr/co/vividnext/sodalive/configs/SecurityConfig.kt
index 986869f..b597a5c 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/configs/SecurityConfig.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/configs/SecurityConfig.kt
@@ -68,6 +68,7 @@ class SecurityConfig(
             .antMatchers("/member/check/nickname").permitAll()
             .antMatchers("/member/signup").permitAll()
             .antMatchers("/member/login").permitAll()
+            .antMatchers("/creator-admin/member/login").permitAll()
             .antMatchers("/member/forgot-password").permitAll()
             .antMatchers("/stplat/terms_of_service").permitAll()
             .antMatchers("/stplat/privacy_policy").permitAll()
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/configs/WebConfig.kt b/src/main/kotlin/kr/co/vividnext/sodalive/configs/WebConfig.kt
index ffbb936..6c38c9c 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/configs/WebConfig.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/configs/WebConfig.kt
@@ -10,6 +10,8 @@ class WebConfig : WebMvcConfigurer {
         registry.addMapping("/**")
             .allowedOrigins(
                 "http://localhost:8888",
+                "https://creator.sodalive.net",
+                "https://test-creator.sodalive.net",
                 "https://test-admin.sodalive.net",
                 "https://admin.sodalive.net"
             )
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/content/CreatorAdminContentController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/content/CreatorAdminContentController.kt
new file mode 100644
index 0000000..47b2491
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/content/CreatorAdminContentController.kt
@@ -0,0 +1,51 @@
+package kr.co.vividnext.sodalive.creator_admin.content
+
+import kr.co.vividnext.sodalive.admin.content.UpdateAdminContentRequest
+import kr.co.vividnext.sodalive.common.ApiResponse
+import kr.co.vividnext.sodalive.common.SodaException
+import kr.co.vividnext.sodalive.member.Member
+import org.springframework.data.domain.Pageable
+import org.springframework.security.access.prepost.PreAuthorize
+import org.springframework.security.core.annotation.AuthenticationPrincipal
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.PutMapping
+import org.springframework.web.bind.annotation.RequestBody
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RequestParam
+import org.springframework.web.bind.annotation.RestController
+
+@RestController
+@PreAuthorize("hasRole('CREATOR')")
+@RequestMapping("/creator-admin/audio-content")
+class CreatorAdminContentController(private val service: CreatorAdminContentService) {
+    @GetMapping("/list")
+    fun getAudioContentList(
+        pageable: Pageable,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(service.getAudioContentList(pageable, member))
+    }
+
+    @GetMapping("/search")
+    fun searchAudioContent(
+        @RequestParam(value = "search_word") searchWord: String,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
+        pageable: Pageable
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(service.searchAudioContent(searchWord, member, pageable))
+    }
+
+    @PutMapping
+    fun modifyAudioContent(
+        @RequestBody request: UpdateAdminContentRequest,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(service.updateAudioContent(request, member))
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/content/CreatorAdminContentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/content/CreatorAdminContentRepository.kt
new file mode 100644
index 0000000..e93087a
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/content/CreatorAdminContentRepository.kt
@@ -0,0 +1,126 @@
+package kr.co.vividnext.sodalive.creator_admin.content
+
+import com.querydsl.core.types.dsl.DateTimePath
+import com.querydsl.core.types.dsl.Expressions
+import com.querydsl.core.types.dsl.StringTemplate
+import com.querydsl.jpa.impl.JPAQueryFactory
+import kr.co.vividnext.sodalive.content.AudioContent
+import kr.co.vividnext.sodalive.content.QAudioContent.audioContent
+import kr.co.vividnext.sodalive.content.hashtag.QAudioContentHashTag.audioContentHashTag
+import kr.co.vividnext.sodalive.content.hashtag.QHashTag.hashTag
+import kr.co.vividnext.sodalive.content.theme.QAudioContentTheme.audioContentTheme
+import org.springframework.data.jpa.repository.JpaRepository
+import java.time.LocalDateTime
+
+interface CreatorAdminContentRepository : JpaRepository<AudioContent, Long>, CreatorAdminAudioContentQueryRepository
+
+interface CreatorAdminAudioContentQueryRepository {
+    fun getAudioContentTotalCount(memberId: Long, searchWord: String = ""): Int
+    fun getAudioContentList(
+        memberId: Long,
+        offset: Long,
+        limit: Long,
+        searchWord: String = ""
+    ): List<GetCreatorAdminContentListItem>
+
+    fun getHashTagList(audioContentId: Long): List<String>
+}
+
+class CreatorAdminAudioContentQueryRepositoryImpl(
+    private val queryFactory: JPAQueryFactory
+) : CreatorAdminAudioContentQueryRepository {
+    override fun getAudioContentTotalCount(memberId: Long, searchWord: String): Int {
+        var where = audioContent.duration.isNotNull
+            .and(audioContent.member.isNotNull)
+            .and(audioContent.isActive.isTrue)
+            .and(audioContent.member.id.eq(memberId))
+
+        if (searchWord.trim().length > 1) {
+            where = where.and(
+                audioContent.title.contains(searchWord)
+                    .or(audioContent.member.nickname.contains(searchWord))
+            )
+        }
+
+        return queryFactory
+            .select(audioContent.id)
+            .from(audioContent)
+            .where(where)
+            .fetch()
+            .size
+    }
+
+    override fun getAudioContentList(
+        memberId: Long,
+        offset: Long,
+        limit: Long,
+        searchWord: String
+    ): List<GetCreatorAdminContentListItem> {
+        var where = audioContent.duration.isNotNull
+            .and(audioContent.member.isNotNull)
+            .and(audioContent.isActive.isTrue)
+            .and(audioContent.member.id.eq(memberId))
+
+        if (searchWord.trim().length > 1) {
+            where = where.and(
+                audioContent.title.contains(searchWord)
+                    .or(audioContent.member.nickname.contains(searchWord))
+            )
+        }
+
+        return queryFactory
+            .select(
+                QGetCreatorAdminContentListItem(
+                    audioContent.id,
+                    audioContent.title,
+                    audioContent.detail,
+                    audioContent.coverImage,
+                    audioContent.member!!.nickname,
+                    audioContentTheme.theme,
+                    audioContent.price,
+                    audioContent.isAdult,
+                    audioContent.duration,
+                    audioContent.content,
+                    formattedDateExpression(audioContent.createdAt)
+                )
+            )
+            .from(audioContent)
+            .innerJoin(audioContent.theme, audioContentTheme)
+            .where(where)
+            .offset(offset)
+            .limit(limit)
+            .orderBy(audioContent.id.desc())
+            .fetch()
+    }
+
+    override fun getHashTagList(audioContentId: Long): List<String> {
+        return queryFactory
+            .select(hashTag.tag)
+            .from(audioContentHashTag)
+            .innerJoin(audioContentHashTag.hashTag, hashTag)
+            .innerJoin(audioContentHashTag.audioContent, audioContent)
+            .where(
+                audioContent.duration.isNotNull
+                    .and(audioContent.member.isNotNull)
+                    .and(audioContentHashTag.audioContent.id.eq(audioContentId))
+            )
+            .fetch()
+    }
+
+    private fun formattedDateExpression(
+        dateTime: DateTimePath<LocalDateTime>,
+        format: String = "%Y-%m-%d"
+    ): StringTemplate {
+        return Expressions.stringTemplate(
+            "DATE_FORMAT({0}, {1})",
+            Expressions.dateTimeTemplate(
+                LocalDateTime::class.java,
+                "CONVERT_TZ({0},{1},{2})",
+                dateTime,
+                "UTC",
+                "Asia/Seoul"
+            ),
+            format
+        )
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/content/CreatorAdminContentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/content/CreatorAdminContentService.kt
new file mode 100644
index 0000000..faf23c0
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/content/CreatorAdminContentService.kt
@@ -0,0 +1,121 @@
+package kr.co.vividnext.sodalive.creator_admin.content
+
+import kr.co.vividnext.sodalive.admin.content.UpdateAdminContentRequest
+import kr.co.vividnext.sodalive.aws.cloudfront.AudioContentCloudFront
+import kr.co.vividnext.sodalive.common.SodaException
+import kr.co.vividnext.sodalive.member.Member
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.data.domain.Pageable
+import org.springframework.data.repository.findByIdOrNull
+import org.springframework.stereotype.Service
+import org.springframework.transaction.annotation.Transactional
+
+@Service
+class CreatorAdminContentService(
+    private val repository: CreatorAdminContentRepository,
+    private val audioContentCloudFront: AudioContentCloudFront,
+
+    @Value("\${cloud.aws.cloud-front.host}")
+    private val coverImageHost: String
+) {
+    fun getAudioContentList(pageable: Pageable, member: Member): GetCreatorAdminContentListResponse {
+        val totalCount = repository.getAudioContentTotalCount(memberId = member.id!!)
+        val audioContentAndThemeList = repository.getAudioContentList(
+            memberId = member.id!!,
+            offset = pageable.offset,
+            limit = pageable.pageSize.toLong()
+        )
+
+        val audioContentList = audioContentAndThemeList
+            .asSequence()
+            .map {
+                val tags = repository
+                    .getHashTagList(audioContentId = it.audioContentId)
+                    .joinToString(" ") { tag -> tag }
+                it.tags = tags
+                it
+            }
+            .map {
+                it.contentUrl = audioContentCloudFront.generateSignedURL(
+                    resourcePath = it.contentUrl,
+                    expirationTime = 1000 * 60 * 60 * (it.remainingTime.split(":")[0].toLong() + 2)
+                )
+                it
+            }
+            .map {
+                it.coverImageUrl = "$coverImageHost/${it.coverImageUrl}"
+                it
+            }
+            .toList()
+
+        return GetCreatorAdminContentListResponse(totalCount, audioContentList)
+    }
+
+    fun searchAudioContent(searchWord: String, member: Member, pageable: Pageable): GetCreatorAdminContentListResponse {
+        if (searchWord.length < 2) throw SodaException("2글자 이상 입력하세요.")
+        val totalCount = repository.getAudioContentTotalCount(
+            memberId = member.id!!,
+            searchWord
+        )
+        val audioContentAndThemeList = repository.getAudioContentList(
+            memberId = member.id!!,
+            offset = pageable.offset,
+            limit = pageable.pageSize.toLong(),
+            searchWord = searchWord
+        )
+
+        val audioContentList = audioContentAndThemeList
+            .asSequence()
+            .map {
+                val tags = repository
+                    .getHashTagList(audioContentId = it.audioContentId)
+                    .joinToString(" ") { tag -> tag }
+                it.tags = tags
+                it
+            }
+            .map {
+                it.contentUrl = audioContentCloudFront.generateSignedURL(
+                    resourcePath = it.contentUrl,
+                    expirationTime = 1000 * 60 * 60 * (it.remainingTime.split(":")[0].toLong() + 2)
+                )
+                it
+            }
+            .map {
+                it.coverImageUrl = "$coverImageHost/${it.coverImageUrl}"
+                it
+            }
+            .toList()
+
+        return GetCreatorAdminContentListResponse(totalCount, audioContentList)
+    }
+
+    @Transactional
+    fun updateAudioContent(request: UpdateAdminContentRequest, member: Member) {
+        val audioContent = repository.findByIdOrNull(id = request.id)
+            ?: throw SodaException("잘못된 콘텐츠 입니다.")
+
+        if (request.isDefaultCoverImage) {
+            audioContent.coverImage = "profile/default_profile.png"
+        }
+
+        if (request.isActive != null) {
+            audioContent.isActive = request.isActive
+        }
+
+        if (request.isAdult != null) {
+            audioContent.isAdult = request.isAdult
+        }
+
+        if (request.isCommentAvailable != null) {
+            audioContent.isCommentAvailable = request.isCommentAvailable
+        }
+
+        if (request.title != null) {
+            audioContent.title = request.title
+        }
+
+        if (request.detail != null) {
+            audioContent.detail = request.detail
+        }
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/content/GetCreatorAdminContentListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/content/GetCreatorAdminContentListResponse.kt
new file mode 100644
index 0000000..efc86d6
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/content/GetCreatorAdminContentListResponse.kt
@@ -0,0 +1,24 @@
+package kr.co.vividnext.sodalive.creator_admin.content
+
+import com.querydsl.core.annotations.QueryProjection
+
+data class GetCreatorAdminContentListResponse(
+    val totalCount: Int,
+    val items: List<GetCreatorAdminContentListItem>
+)
+
+data class GetCreatorAdminContentListItem @QueryProjection constructor(
+    val audioContentId: Long,
+    val title: String,
+    val detail: String,
+    var coverImageUrl: String,
+    val creatorNickname: String,
+    val theme: String,
+    val price: Int,
+    val isAdult: Boolean,
+    val remainingTime: String,
+    var contentUrl: String,
+    val date: String
+) {
+    var tags: String = ""
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/member/CreatorAdminMemberController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/member/CreatorAdminMemberController.kt
new file mode 100644
index 0000000..f64773c
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/member/CreatorAdminMemberController.kt
@@ -0,0 +1,31 @@
+package kr.co.vividnext.sodalive.creator_admin.member
+
+import kr.co.vividnext.sodalive.common.ApiResponse
+import kr.co.vividnext.sodalive.common.SodaException
+import kr.co.vividnext.sodalive.member.Member
+import kr.co.vividnext.sodalive.member.login.LoginRequest
+import org.springframework.security.access.prepost.PreAuthorize
+import org.springframework.security.core.annotation.AuthenticationPrincipal
+import org.springframework.web.bind.annotation.PostMapping
+import org.springframework.web.bind.annotation.RequestBody
+import org.springframework.web.bind.annotation.RequestHeader
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RestController
+
+@RestController
+@RequestMapping("/creator-admin/member")
+class CreatorAdminMemberController(private val service: CreatorAdminMemberService) {
+    @PostMapping("/login")
+    fun login(@RequestBody loginRequest: LoginRequest) = service.login(loginRequest)
+
+    @PostMapping("/logout")
+    @PreAuthorize("hasRole('CREATOR')")
+    fun logout(
+        @RequestHeader("Authorization") token: String,
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(service.logout(token.removePrefix("Bearer "), member.id!!))
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/member/CreatorAdminMemberService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/member/CreatorAdminMemberService.kt
new file mode 100644
index 0000000..9ecff6e
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator_admin/member/CreatorAdminMemberService.kt
@@ -0,0 +1,93 @@
+package kr.co.vividnext.sodalive.creator_admin.member
+
+import kr.co.vividnext.sodalive.common.ApiResponse
+import kr.co.vividnext.sodalive.common.SodaException
+import kr.co.vividnext.sodalive.jwt.TokenProvider
+import kr.co.vividnext.sodalive.member.MemberRepository
+import kr.co.vividnext.sodalive.member.MemberRole
+import kr.co.vividnext.sodalive.member.login.LoginRequest
+import kr.co.vividnext.sodalive.member.login.LoginResponse
+import kr.co.vividnext.sodalive.member.token.MemberTokenRepository
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.data.repository.findByIdOrNull
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
+import org.springframework.security.core.context.SecurityContextHolder
+import org.springframework.stereotype.Service
+import org.springframework.transaction.annotation.Transactional
+import java.util.concurrent.locks.ReentrantReadWriteLock
+import kotlin.concurrent.write
+
+@Service
+class CreatorAdminMemberService(
+    private val repository: MemberRepository,
+    private val tokenRepository: MemberTokenRepository,
+    private val tokenProvider: TokenProvider,
+    private val authenticationManagerBuilder: AuthenticationManagerBuilder,
+
+    @Value("\${cloud.aws.cloud-front.host}")
+    private val cloudFrontHost: String
+) {
+
+    private val tokenLocks: MutableMap<Long, ReentrantReadWriteLock> = mutableMapOf()
+
+    fun login(request: LoginRequest): ApiResponse<LoginResponse> {
+        return ApiResponse.ok(
+            message = "로그인 되었습니다.",
+            data = login(request.email, request.password)
+        )
+    }
+
+    @Transactional
+    fun logout(token: String, memberId: Long) {
+        val member = repository.findByIdOrNull(memberId)
+            ?: throw SodaException("로그인 정보를 확인해주세요.")
+
+        member.pushToken = null
+
+        val lock = getOrCreateLock(memberId = memberId)
+        lock.write {
+            val memberToken = tokenRepository.findByIdOrNull(memberId)
+                ?: throw SodaException("로그인 정보를 확인해주세요.")
+
+            memberToken.tokenSet.remove(token)
+            tokenRepository.save(memberToken)
+        }
+    }
+
+    private fun login(email: String, password: String): LoginResponse {
+        val member = repository.findByEmail(email = email) ?: throw SodaException("로그인 정보를 확인해주세요.")
+        if (!member.isActive) {
+            throw SodaException("탈퇴한 계정입니다.\n고객센터로 문의해 주시기 바랍니다.")
+        }
+
+        if (member.role != MemberRole.CREATOR) {
+            throw SodaException("로그인 정보를 확인해주세요.")
+        }
+
+        val authenticationToken = UsernamePasswordAuthenticationToken(email, password)
+        val authentication = authenticationManagerBuilder.`object`.authenticate(authenticationToken)
+        SecurityContextHolder.getContext().authentication = authentication
+
+        val jwt = tokenProvider.createToken(
+            authentication = authentication,
+            memberId = member.id!!
+        )
+
+        return LoginResponse(
+            userId = member.id!!,
+            token = jwt,
+            nickname = member.nickname,
+            email = member.email,
+            profileImage = if (member.profileImage != null) {
+                "$cloudFrontHost/${member.profileImage}"
+            } else {
+                "$cloudFrontHost/profile/default-profile.png"
+            }
+        )
+    }
+
+    private fun getOrCreateLock(memberId: Long): ReentrantReadWriteLock {
+        return tokenLocks.computeIfAbsent(memberId) { ReentrantReadWriteLock() }
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuController.kt
index 5146119..d9b8e7b 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuController.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuController.kt
@@ -12,6 +12,6 @@ import org.springframework.web.bind.annotation.RestController
 @RequestMapping("/menu")
 class MenuController(private val service: MenuService) {
     @GetMapping
-    @PreAuthorize("hasAnyRole('AGENT', 'ADMIN')")
+    @PreAuthorize("hasAnyRole('AGENT', 'ADMIN', 'CREATOR')")
     fun getMenus(@AuthenticationPrincipal user: User) = ApiResponse.ok(service.getMenus(user))
 }