Http Router 서비스
가장 흔하게 쓰이는 서비스 중 하나가 HTTP 라우터 서비스예요. 이 서비스는 다른 플러그인이 소비할 수 있도록 HTTP 엔드포인트를 노출하는 데 사용돼요.
출처: 문서
본문
가장 흔하게 쓰이는 서비스 중 하나가 HTTP 라우터 서비스예요. 이 서비스는 다른 플러그인이 소비할 수 있도록 HTTP 엔드포인트를 노출하는 데 사용돼요.
서비스 사용하기
다음 예시는 example 플러그인에 HTTP 라우터를 등록하는 방법을 보여줘요. 이 단일 라우트는 /api/example/hello 경로에서 사용할 수 있게 돼요.
import { coreServices, createBackendPlugin } from '@backstage/backend-plugin-api';
import { Router } from 'express';
createBackendPlugin({
pluginId: 'example',
register(env) {
env.registerInit({
deps: {
http: coreServices.httpRouter,
},
async init({ http }) {
const router = Router();
router.get('/hello', (_req, res) => {
res.status(200).json({ hello: 'world' });
});
// Registers the router at the /api/example path
http.use(router);
},
});
},
});
이 서비스는 라우트에 적용되는 인증(auth) 정책을 추적하는 일도 담당해요. 기본 정책은 모든 수신 요청에 인증이 포함되도록 요구하며, 서비스 자격 증명과 사용자 자격 증명을 모두 허용해요(제한된 액세스 토큰은 제외). 라우트를 등록할 때 이 정책을 덮어쓸 수도 있어요. 다음은 특정 라우트에서 위험할 수 있는 미인증 접근을 허용하는 예시예요.
http.addAuthPolicy({
path: '/static/:id',
allow: 'unauthenticated',
});
경로는 라우트에서 사용한 형식과 정확히 동일하며 자리표시자(placeholder)도 포함한다는 점에 주의하세요.
플러그인이 쿠키 기반 접근을 사용하는 경우(드문 경우) 다음과 같이 허용해야 해요.
http.addAuthPolicy({
path: '/static/:id',
allow: 'user-cookie',
});
그런 라우트에서는 들어오는 자격 증명에 접근할 때 auth 및 httpAuth 서비스를 사용하면서 allowLimitedAccess: true도 지정해야 해요.
속도 제한(Rate limiting)
속도 제한을 사용하면 사용자가 백엔드에 보낼 수 있는 요청 수를 제한할 수 있어요. 이는 DDOS 같은 각종 네트워크 공격을 차단하는 데 유용해요.
속도 제한을 활성화하려면 설정에 다음을 추가하세요.
backend:
rateLimit: true
속도 제한 매개변수도 플러그인별로 추가로 구성할 수 있어요.
backend:
rateLimit:
global: true # Enables or disables rate limit for all plugins
window: 6s # Time window for rate limiting for single client
incomingRequestLimit: 100 # Number of requests to accept from one client during time window
ipAllowList: ['127.0.0.1'] # IPs to bypass rate limiting
skipSuccessfulRequests: false # Rate limit successful requests
skipFailedRequests: false # Rate limit failed requests
plugin:
# Plugin specific rate limiting
catalog:
window: 3s
incomingRequestLimit: 50
기본적으로 속도 제한은 인스턴스 단위로 적용되며 요청 수는 메모리에 저장돼요. 이 정보를 모든 Backstage 인스턴스에서 공유하려면 속도 제한 저장소를 구성해야 해요.
backend:
rateLimit:
global: true
store:
type: redis
connection: redis://127.0.0.1:16379
인스턴스가 프록시 뒤에서 동작한다면 속도 제한이 클라이언트를 구분할 수 있도록 백엔드가 프록시를 신뢰하도록 구성해야 해요.
backend:
trustProxy: true
trust proxy 구성과 사용 가능한 옵션에 대한 자세한 내용은 express 문서를 참고하세요.
서비스 구성하기
더 고급 사용자 지정을 위해 @backstage/backend-defaults/httpRouter 패키지에는 구성 서비스의 구현을 사용자 지정할 수 있는 몇 가지 API가 있어요. 기본 구현은 @backstage/backend-defaults/httpRouter에서 내보낸 모든 미들웨어를 사용하는데, 여기에는 createLifecycleMiddleware, createAuthIntegrationRouter, createCredentialsBarrier, createCookieAuthRefreshMiddleware가 포함돼요. 이것들을 사용해 나만의 httpRouter 서비스 구현을 만들 수 있어요. 예를 들어 모든 플러그인에 사용자 지정 헬스 체크 라우트를 추가하는 방법은 다음과 같아요.
import {
createLifecycleMiddleware,
createCookieAuthRefreshMiddleware,
createCredentialsBarrier,
createAuthIntegrationRouter,
createRateLimitMiddleware,
} from '@backstage/backend-defaults/httpRouter';
import PromiseRouter from 'express-promise-router';
import { Handler } from 'express';
import {
createServiceFactory,
coreServices,
HttpRouterServiceAuthPolicy,
} from '@backstage/backend-plugin-api';
const backend = createBackend();
backend.add(
createServiceFactory({
service: coreServices.httpRouter,
initialization: 'always',
deps: {
plugin: coreServices.pluginMetadata,
config: coreServices.rootConfig,
lifecycle: coreServices.lifecycle,
rootHttpRouter: coreServices.rootHttpRouter,
auth: coreServices.auth,
httpAuth: coreServices.httpAuth,
},
async factory({
auth,
httpAuth,
config,
plugin,
rootHttpRouter,
lifecycle,
}) {
const router = PromiseRouter();
// Optional rate limiting middleware
router.use(
createRateLimitMiddleware({ pluginId: plugin.getId(), config }),
);
rootHttpRouter.use(`/api/${plugin.getId()}`, router);
const credentialsBarrier = createCredentialsBarrier({
httpAuth,
config,
});
router.use(createAuthIntegrationRouter({ auth }));
router.use(createLifecycleMiddleware({ config, lifecycle }));
router.use(credentialsBarrier.middleware);
router.use(createCookieAuthRefreshMiddleware({ auth, httpAuth }));
// Add a custom healthcheck endpoint for all plugins.
router.use('/health', (_, res) => {
res.status(200);
});
return {
use(handler: Handler): void {
router.use(handler);
},
addAuthPolicy(policy: HttpRouterServiceAuthPolicy): void {
credentialsBarrier.addAuthPolicy(policy);
},
};
},
}),
);