<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Superset Admin</title><subtitle>Перепубликация статей с заблоченных в РФ сайтов. 
Подписывайтесь на канал в Telegram https://t.me/apache_superset_bi</subtitle><author><name>Superset Admin</name></author><id>https://teletype.in/atom/apache_superset</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/apache_superset?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@apache_superset?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=apache_superset"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/apache_superset?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-04-24T17:45:20.166Z</updated><entry><id>apache_superset:apache-superset-bi-tool-chto-vnedrit-power-bi</id><link rel="alternate" type="text/html" href="https://teletype.in/@apache_superset/apache-superset-bi-tool-chto-vnedrit-power-bi?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=apache_superset"></link><title>Приветствуем Вас в Мире Apache Superset BI: Лучшем Инструменте для Бизнес-Аналитики</title><published>2024-03-27T19:34:43.153Z</published><updated>2024-03-27T19:34:43.153Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/82/f4/82f4735f-c98c-4b3f-9652-3f6174d12e7a.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/d2/55/d2553dee-004a-43a8-bf17-589d17e9b321.png&quot;&gt;🚀 Переходите на Apache Superset: Лучший BI инструмент в России после ухода Power BI! 📊💡
👉 https://t.me/apache_superset_bi 👈</summary><content type="html">
  &lt;p id=&quot;4szs&quot;&gt;🚀 &lt;strong&gt;Переходите на Apache Superset: Лучший BI инструмент в России после ухода Power BI!&lt;/strong&gt; 📊💡&lt;br /&gt;👉 &lt;a href=&quot;https://t.me/apache_superset_bi&quot; target=&quot;_blank&quot;&gt;https://t.me/apache_superset_bi &lt;/a&gt;👈&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;WAt8&quot;&gt;WebSite: &lt;a href=&quot;https://superset-bi.ru&quot; target=&quot;_blank&quot;&gt;https://superset-bi.ru&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;pP7C&quot;&gt;&lt;strong&gt;Вступление:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;153Z&quot;&gt;В мире быстро развивающейся технологии и данных, принятие обоснованных решений на основе фактических данных является ключом к успеху для любого бизнеса. В этой связи становится очевидной необходимость в современных и мощных инструментах для анализа данных. И вот на сцену выходит Apache Superset BI - инновационный инструмент, предоставляющий компаниям всё необходимое для эффективного анализа данных и принятия обоснованных решений.&lt;/p&gt;
  &lt;figure id=&quot;wYdw&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d2/55/d2553dee-004a-43a8-bf17-589d17e9b321.png&quot; width=&quot;712&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;yrlm&quot;&gt;&lt;strong&gt;Описание Преимуществ Apache Superset BI:&lt;/strong&gt;&lt;/p&gt;
  &lt;ol id=&quot;JiUL&quot;&gt;
    &lt;li id=&quot;UIVG&quot;&gt;&lt;strong&gt;Открытый исходный код для свободы и гибкости:&lt;/strong&gt; В отличие от многих коммерческих решений, Apache Superset BI предоставляет полную свободу и гибкость благодаря своему открытому исходному коду. Это означает, что пользователи могут настраивать и расширять функциональность инструмента в соответствии с их уникальными потребностями и требованиями бизнеса.&lt;/li&gt;
    &lt;li id=&quot;JsgO&quot;&gt;&lt;strong&gt;Богатый набор возможностей для визуализации и анализа данных:&lt;/strong&gt; Apache Superset BI предлагает широкий выбор визуализаций и инструментов для анализа данных, позволяя пользователям визуализировать и понимать свои данные на новом уровне. Благодаря этому, компании могут легко выявлять тренды, прогнозировать будущие тенденции и принимать обоснованные решения на основе фактических данных.&lt;/li&gt;
    &lt;li id=&quot;kyla&quot;&gt;&lt;strong&gt;Интерактивные возможности для удобства использования:&lt;/strong&gt; Apache Superset BI предлагает широкий спектр интерактивных возможностей, позволяя пользователям взаимодействовать с данными и аналитическими инструментами более эффективно. Это включает в себя возможность фильтрации данных, просмотра деталей, создания динамических дашбордов и многое другое.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;zvzM&quot;&gt;&lt;strong&gt;Применение Apache Superset BI в Реальном Мире:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;4ebE&quot;&gt;Apache Superset BI находит широкое применение в различных отраслях и сферах бизнеса. Он используется для мониторинга производительности продуктов, анализа рыночных трендов, оптимизации бизнес-процессов, а также для принятия стратегических решений на основе данных.&lt;/p&gt;
  &lt;p id=&quot;70Ox&quot;&gt;&lt;strong&gt;Заключение:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;3LPu&quot;&gt;Apache Superset BI представляет собой мощный и инновационный инструмент для бизнес-аналитики, который помогает компаниям извлекать ценную информацию из данных и принимать обоснованные решения на основе фактических данных. Присоединяйтесь к миру Apache Superset BI уже сегодня и дайте вашему бизнесу мощный инструмент для анализа данных!&lt;/p&gt;

</content></entry><entry><id>apache_superset:power-bi-alternative-russia-apache-superset-2024</id><link rel="alternate" type="text/html" href="https://teletype.in/@apache_superset/power-bi-alternative-russia-apache-superset-2024?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=apache_superset"></link><title>🚀 Переходите на Apache Superset: Лучший BI инструмент в России после ухода Power BI! 📊💡</title><published>2024-03-27T19:30:38.317Z</published><updated>2024-03-27T19:35:55.469Z</updated><tt:hashtag>apachesuperset</tt:hashtag><tt:hashtag>бизнесаналитика</tt:hashtag><tt:hashtag>анализданных</tt:hashtag><tt:hashtag>bi</tt:hashtag><tt:hashtag>открытыйисходныйкод</tt:hashtag><tt:hashtag>инновации</tt:hashtag><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/cc/52/cc526992-d352-4218-b95f-3cb30cdb5263.png&quot;&gt;🚀 Объявляем! 🚀</summary><content type="html">
  &lt;p id=&quot;TMOj&quot;&gt;🚀 Объявляем! 🚀&lt;/p&gt;
  &lt;p id=&quot;Bpwb&quot;&gt;Пришло время обновить свои инструменты бизнес-аналитики! 📊 Если вы ищете лучший альтернативный BI инструмент в России для перехода с ушедшего с рынка Power BI, то ваш выбор должен быть Apache Superset! 💡&lt;/p&gt;
  &lt;figure id=&quot;h9kx&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/cc/52/cc526992-d352-4218-b95f-3cb30cdb5263.png&quot; width=&quot;800&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;eNaR&quot;&gt;🌟 Почему Apache Superset?&lt;/p&gt;
  &lt;ol id=&quot;lpk5&quot;&gt;
    &lt;li id=&quot;Bluz&quot;&gt;&lt;strong&gt;Открытый исходный код&lt;/strong&gt;: Apache Superset - это инструмент с открытым исходным кодом, что означает, что вы получаете полную гибкость и контроль над вашими данными и аналитическими инструментами.&lt;/li&gt;
    &lt;li id=&quot;UDOf&quot;&gt;&lt;strong&gt;Богатый набор возможностей&lt;/strong&gt;: С Apache Superset вы получаете доступ к широкому спектру визуализаций, интеграции с различными источниками данных, а также возможность создания интерактивных дашбордов и отчетов.&lt;/li&gt;
    &lt;li id=&quot;bbBe&quot;&gt;&lt;strong&gt;Активное сообщество&lt;/strong&gt;: Вас ждет огромное сообщество пользователей и разработчиков Apache Superset, готовых поделиться знаниями, решить ваши вопросы и поддержать вас на пути к успешному использованию инструмента.&lt;/li&gt;
    &lt;li id=&quot;vhWS&quot;&gt;&lt;strong&gt;Легкость в использовании&lt;/strong&gt;: Apache Superset предлагает интуитивно понятный пользовательский интерфейс, что делает работу с данными и создание визуализаций быстрым и удобным процессом.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;XE4r&quot;&gt;🌐 Не упустите возможность обновить свои инструменты бизнес-аналитики и перейти на Apache Superset - лучший выбор для вашего бизнеса! Присоединяйтесь к сообществу Apache Superset уже сегодня и дайте вашему бизнесу мощный инструмент для анализа данных! 🚀💼&lt;/p&gt;
  &lt;tt-tags id=&quot;BZkf&quot;&gt;
    &lt;tt-tag name=&quot;apachesuperset&quot;&gt;#apachesuperset&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;бизнесаналитика&quot;&gt;#бизнесаналитика&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;анализданных&quot;&gt;#анализданных&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;bi&quot;&gt;#bi&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;открытыйисходныйкод&quot;&gt;#открытыйисходныйкод&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;инновации&quot;&gt;#инновации&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;1gp2&quot;&gt;Присоединяйтесь к нам, чтобы быть в курсе всего, что касается Apache Superset и бизнес-аналитики! Просто перейдите по ссылке: &lt;/p&gt;
  &lt;p id=&quot;uirg&quot;&gt;&lt;a href=&quot;https://t.me/apache_superset_bi&quot; target=&quot;_blank&quot;&gt;https://t.me/apache_superset_bi&lt;/a&gt;&lt;/p&gt;
  &lt;h2 id=&quot;VdQ8&quot;&gt;APACHE SUPERSET КАНАЛ ПРО ВНЕДРЕНИЕ BI ИНСТРУМЕНТА В РОССИИ&lt;/h2&gt;
  &lt;p id=&quot;a3MU&quot;&gt;👉 &lt;a href=&quot;https://t.me/apache_superset_bi&quot; target=&quot;_blank&quot;&gt;https://t.me/apache_superset_bi &lt;/a&gt;👈&lt;/p&gt;
  &lt;p id=&quot;cULI&quot;&gt;👉 &lt;a href=&quot;https://t.me/apache_superset_bi&quot; target=&quot;_blank&quot;&gt;https://t.me/apache_superset_bi&lt;/a&gt; 👈&lt;/p&gt;
  &lt;p id=&quot;jm5c&quot;&gt;👉 &lt;a href=&quot;https://t.me/apache_superset_bi&quot; target=&quot;_blank&quot;&gt;https://t.me/apache_superset_bi&lt;/a&gt; 👈&lt;/p&gt;

</content></entry><entry><id>apache_superset:apache-superset-yandex-datalens</id><link rel="alternate" type="text/html" href="https://teletype.in/@apache_superset/apache-superset-yandex-datalens?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=apache_superset"></link><title>Yandex Datalens и Apache Superset</title><published>2024-03-27T19:23:50.600Z</published><updated>2024-03-27T19:38:13.983Z</updated><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/59/6e/596e33f0-ae06-45a1-a915-4248a0d06813.png&quot;&gt;В мире современного бизнеса, особенно в цифровую эпоху, данные играют ключевую роль в принятии стратегических решений. В этой связи возникает потребность в эффективных инструментах анализа данных, которые могут помочь компаниям извлечь ценную информацию из больших объемов данных. В ответ на эту потребность был разработан сервис DataLens - инновационный инструмент для бизнес-аналитики.</summary><content type="html">
  &lt;h2 id=&quot;tsyG&quot;&gt;DataLens: Инновационный Сервис для Бизнес-Аналитики&lt;/h2&gt;
  &lt;p id=&quot;Ecye&quot;&gt;В мире современного бизнеса, особенно в цифровую эпоху, данные играют ключевую роль в принятии стратегических решений. В этой связи возникает потребность в эффективных инструментах анализа данных, которые могут помочь компаниям извлечь ценную информацию из больших объемов данных. В ответ на эту потребность был разработан сервис DataLens - инновационный инструмент для бизнес-аналитики.&lt;/p&gt;
  &lt;h3 id=&quot;ZlyT&quot;&gt;Знакомство с DataLens&lt;/h3&gt;
  &lt;p id=&quot;MwdN&quot;&gt;DataLens - это мощный сервис для бизнес-аналитики, который предоставляет пользователям возможность подключаться к различным источникам данных, строить визуализации, создавать дашборды и делиться результатами анализа. Благодаря DataLens компании могут отслеживать различные продуктовые и бизнес-метрики непосредственно из источников данных, что позволяет принимать обоснованные решения на основе фактических данных.&lt;/p&gt;
  &lt;h3 id=&quot;ryfm&quot;&gt;Ключевые Компоненты DataLens&lt;/h3&gt;
  &lt;p id=&quot;dnx1&quot;&gt;DataLens состоит из нескольких ключевых компонентов, которые обеспечивают полный цикл работы с данными:&lt;/p&gt;
  &lt;ol id=&quot;9LMg&quot;&gt;
    &lt;li id=&quot;plM7&quot;&gt;&lt;strong&gt;Подключение&lt;/strong&gt;: Это набор параметров, который позволяет пользователям получить доступ к различным источникам данных. Пользователи могут настроить подключения к базам данных, веб-сервисам, файлам и другим источникам данных.&lt;/li&gt;
    &lt;li id=&quot;DptB&quot;&gt;&lt;strong&gt;Датасет&lt;/strong&gt;: Компонент, который описывает набор данных из выбранного источника. Датасет позволяет пользователям работать с конкретными данными, определяя поля, типы данных и другие атрибуты.&lt;/li&gt;
    &lt;li id=&quot;8JxS&quot;&gt;&lt;strong&gt;Чарт&lt;/strong&gt;: Это визуализация данных из выбранного источника или датасета. DataLens предоставляет различные типы чартов, такие как таблицы, диаграммы и карты, которые помогают пользователям визуализировать и анализировать данные более наглядно.&lt;/li&gt;
    &lt;li id=&quot;0kWn&quot;&gt;&lt;strong&gt;Дашборд&lt;/strong&gt;: Набор чартов, селекторов для фильтрации данных и текстовых блоков, который позволяет пользователям создавать интерактивные дашборды для мониторинга ключевых метрик и отслеживания изменений в реальном времени.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;b0qz&quot;&gt;Но есть другой, намного удобнее инструмент - APACHE SUPESET&lt;/h2&gt;
  &lt;figure id=&quot;Ey39&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/59/6e/596e33f0-ae06-45a1-a915-4248a0d06813.png&quot; width=&quot;1928&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;ZIJZ&quot;&gt;DataLens vs. Apache Superset: Как сравнить два инструмента бизнес-аналитики&lt;/h2&gt;
  &lt;p id=&quot;FLoG&quot;&gt;Помимо DataLens, существует еще один известный open source инструмент для бизнес-аналитики - Apache Superset. В последнее время Apache Superset набирает популярность благодаря своей гибкости, мощным возможностям и открытому исходному коду. Давайте рассмотрим некоторые аспекты, в которых Apache Superset может превзойти DataLens, и почему читателям стоит обратить внимание на этот инновационный инструмент.&lt;/p&gt;
  &lt;figure id=&quot;uUq7&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/90/7e/907e5a79-ba04-438e-8fc7-bfa080d15573.png&quot; width=&quot;800&quot; /&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;YW2Z&quot;&gt;1. Гибкость и Расширяемость&lt;/h3&gt;
  &lt;p id=&quot;uxTZ&quot;&gt;Одним из ключевых преимуществ Apache Superset является его открытый исходный код, что делает его крайне гибким и расширяемым инструментом. Пользователи могут легко настраивать и расширять функциональность Superset в соответствии с их потребностями. Это отличается от DataLens, который может иметь ограниченные возможности кастомизации из-за своего закрытого характера.&lt;/p&gt;
  &lt;h3 id=&quot;xRfY&quot;&gt;2. Богатый Набор Визуализаций&lt;/h3&gt;
  &lt;p id=&quot;Zykq&quot;&gt;Apache Superset предлагает широкий выбор визуализаций, включая различные типы графиков, диаграмм, карт и многие другие. Этот богатый набор визуализаций делает анализ данных более наглядным и информативным. В сравнении с этим, DataLens может иметь ограниченный набор визуализаций или меньшую гибкость в настройке визуализаций.&lt;/p&gt;
  &lt;h3 id=&quot;8iGx&quot;&gt;3. Активное Сообщество и Поддержка&lt;/h3&gt;
  &lt;p id=&quot;Zxmh&quot;&gt;Apache Superset поддерживается активным сообществом разработчиков и пользователей, что означает быстрое обновление, исправление ошибок и разработку новых функций. Это обеспечивает стабильную и надежную поддержку для пользователей. В то время как DataLens, возможно, имеет ограниченную поддержку или ресурсы для разработки и обновления.&lt;/p&gt;
  &lt;h3 id=&quot;SoP4&quot;&gt;Попробуйте Apache Superset уже сегодня!&lt;/h3&gt;
  &lt;p id=&quot;cNFL&quot;&gt;Если вы ищете мощный и гибкий инструмент для бизнес-аналитики, то Apache Superset - отличный выбор. Его открытый исходный код, богатый набор визуализаций и активное сообщество делают его идеальным решением для различных потребностей аналитики данных. Перейдите на сайт &lt;a href=&quot;https://superset-bi.ru/&quot; target=&quot;_blank&quot;&gt;superset-bi.ru&lt;/a&gt; и попробуйте Apache Superset уже сегодня!&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;zXnG&quot;&gt;🚀 Присоединяйтесь к нашему &lt;a href=&quot;https://t.me/apache_superset_bi&quot; target=&quot;_blank&quot;&gt;телеграм-каналу &amp;quot;Apache Superset BI&amp;quot;!&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;xZ5f&quot;&gt;Вы интересуетесь инструментами бизнес-аналитики? Хотите быть в курсе последних новостей, обновлений и полезных советов по использованию Apache Superset? Тогда наш телеграм-канал для вас!&lt;/p&gt;
  &lt;p id=&quot;laAP&quot;&gt;📊 В &amp;quot;Apache Superset BI&amp;quot; вы найдете:&lt;/p&gt;
  &lt;p id=&quot;XO8r&quot;&gt;🔍 Обзоры новых функций и возможностей Apache Superset. 📈 Практические советы и руководства по использованию инструментов бизнес-аналитики. 💡 Статьи и рекомендации от экспертов в области аналитики данных. 🔄 Обсуждения и деловые истории успеха от пользователей Apache Superset.&lt;/p&gt;
  &lt;p id=&quot;7NfF&quot;&gt;Присоединяйтесь к нам, чтобы быть в курсе всего, что касается Apache Superset и бизнес-аналитики! Просто перейдите по ссылке: &lt;a href=&quot;https://t.me/apache_superset_bi&quot; target=&quot;_blank&quot;&gt;https://t.me/apache_superset_bi&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;4s6u&quot;&gt;Присоединяйтесь прямо сейчас и станьте частью нашего сообщества! 📊🚀&lt;/p&gt;

</content></entry><entry><id>apache_superset:building-a-data-warehouse-with-clickhouse-superset</id><link rel="alternate" type="text/html" href="https://teletype.in/@apache_superset/building-a-data-warehouse-with-clickhouse-superset?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=apache_superset"></link><title>Как мы создавали внутреннее хранилище данных в ClickHouse</title><published>2024-02-10T06:38:11.602Z</published><updated>2024-02-10T06:45:35.401Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/ef/a1/efa170fb-f326-4cfc-84c6-ad52f9e1ead7.png"></media:thumbnail><category term="apache-superset-click-house" label="Apache Superset ClickHouse"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/8a/22/8a226afc-802a-4c9d-91fb-2e78032822a9.png&quot;&gt;Перевод статьи: https://clickhouse.com/blog/building-a-data-warehouse-with-clickhouse</summary><content type="html">
  &lt;p id=&quot;PuNz&quot;&gt;&lt;strong&gt;Перевод статьи:&lt;/strong&gt; &lt;a href=&quot;https://clickhouse.com/blog/building-a-data-warehouse-with-clickhouse&quot; target=&quot;_blank&quot;&gt;https://clickhouse.com/blog/building-a-data-warehouse-with-clickhouse&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;mOjB&quot;&gt;&lt;strong&gt;Подписывайтесь на телеграм канал Apache Superset: &lt;/strong&gt;&lt;a href=&quot;https://t.me/apache_superset_bi&quot; target=&quot;_blank&quot;&gt;https://t.me/apache_superset_bi&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;eW11&quot;&gt;В ClickHouse мы видим свою миссию в предоставлении нашим клиентам и пользователям сверхбыстрой облачной аналитической базы данных, которую можно использовать для внутренней аналитики и аналитики, ориентированной на клиентов. &lt;a href=&quot;https://clickhouse.cloud/signUp&quot; target=&quot;_blank&quot;&gt;ClickHouse Cloud&lt;/a&gt; позволяет нашим клиентам хранить и обрабатывать практически неограниченные объемы данных, что помогает им принимать решения на основе данных. Принятие решений, основанных на фактах, а не на предположениях, сегодня имеет решающее значение для большинства успешных предприятий.&lt;/p&gt;
  &lt;p id=&quot;l0iA&quot;&gt;Конечно, внутри нашей команды мы придерживаемся такого же подхода. Разработка и эксплуатация нашей облачной базы данных генерирует огромный объем данных, которые можно использовать для планирования мощности, ценообразования, лучшего понимания потребностей наших клиентов и финансовой отчетности. Десятки источников данных, сотни терабайт и около сотни BI-пользователей и специальных пользователей… И угадайте, что для этого мы используем ClickHouse Cloud :)&lt;/p&gt;
  &lt;p id=&quot;xuMq&quot;&gt;В этом посте я расскажу, как устроено наше внутреннее хранилище данных (DWH), какой стек мы используем и как наше хранилище данных будет развиваться в ближайшие несколько месяцев.&lt;/p&gt;
  &lt;h2 id=&quot;requirements-and-data-sources&quot;&gt;Требования и источники данных&lt;/h2&gt;
  &lt;p id=&quot;VZQ5&quot;&gt;Мы &lt;a href=&quot;https://clickhouse.com/blog/building-clickhouse-cloud-from-scratch-in-a-year&quot; target=&quot;_blank&quot;&gt;запустили&lt;/a&gt; ClickHouse Cloud в режиме Private Preview в мае 2022 года и в то же время поняли, что хотим лучше понимать наших клиентов: как они используют наш сервис, с какими трудностями они сталкиваются, как мы можем им помочь и как мы можем сделать наши цены доступны и разумны для них. Для этого нам нужно было собирать и обрабатывать данные из нескольких внутренних источников данных: плоскости данных, которая отвечает за работу модулей базы данных клиента, плоскости управления, которая отвечает за пользовательский интерфейс и операции с базой данных, а также AWS Billing, которая дает нам точные затраты на выполнение рабочих нагрузок клиентов.&lt;/p&gt;
  &lt;p id=&quot;409U&quot;&gt;Был короткий период времени, когда наш вице-президент по продуктам Таня Брагин ежедневно вручную анализировала рабочие нагрузки наших клиентов в Excel, используя поиск. Мне, как бывшему архитектору СХД, было обидно, что ей пришлось так бороться, и в результате родилась первая концепция внутренней СХД.&lt;/p&gt;
  &lt;p id=&quot;wnGH&quot;&gt;При разработке системы перед нами стоял ряд важных задач, которые мы стремились поддержать наших внутренних заинтересованных сторон, некоторые из которых перечислены ниже.&lt;/p&gt;
  &lt;figure id=&quot;K0SH&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/6a/be/6abef232-8347-4222-a2b8-c9eb59ce48bd.png&quot; width=&quot;1103&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;0rBB&quot;&gt;&lt;strong&gt;Команда продукта&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;M70i&quot;&gt;Отслеживание показателей конверсии и удержания, использования функций, размера сервисов, их использования и выявления наиболее распространенных проблем. Проведение глубокого специального анализа.&lt;/p&gt;
  &lt;p id=&quot;K0WE&quot;&gt;&lt;strong&gt;Операционная группа&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;ydvt&quot;&gt;Отслеживание приблизительного дохода и предоставление доступа к некоторым данным Salesforce в режиме только для чтения для большинства сотрудников компании.&lt;/p&gt;
  &lt;p id=&quot;ba7g&quot;&gt;&lt;strong&gt;Отдел продаж&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;egJk&quot;&gt;Просмотр настроек и использования конкретных клиентов: сколько услуг, сколько данных, типичные проблемы и т. д.&lt;/p&gt;
  &lt;p id=&quot;9dup&quot;&gt;&lt;strong&gt;Инженерная команда&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;icEi&quot;&gt;Настройка нашего автомасштабирования, отслеживание частоты ошибок запросов и использования функций БД.&lt;/p&gt;
  &lt;p id=&quot;YZil&quot;&gt;&lt;strong&gt;Группа поддержки&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;232U&quot;&gt;Просмотр конкретной настройки клиента: услуги, использование, объем данных и т. д.&lt;/p&gt;
  &lt;p id=&quot;UGnc&quot;&gt;&lt;strong&gt;Маркетинговая команда&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;Jafq&quot;&gt;Отслеживание коэффициентов конверсии на вершине воронки, стоимости привлечения клиентов и других маркетинговых показателей.&lt;/p&gt;
  &lt;p id=&quot;9JDj&quot;&gt;&lt;strong&gt;Команда экономии затрат&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;ckCE&quot;&gt;Анализ затрат CSP и активная оптимизация наших обязательств CSP.&lt;/p&gt;
  &lt;p id=&quot;rWj2&quot;&gt;&lt;strong&gt;команда CI-CD&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;a74n&quot;&gt;Отслеживание затрат CI-CD&lt;/p&gt;
  &lt;p id=&quot;AJFH&quot;&gt;&lt;strong&gt;Примечание. В нашем внутреннем хранилище данных мы не собираем, не храним и не обрабатываем какую-либо часть данных наших клиентов (большая часть которых зашифрована), например данные таблиц, текст запроса, сетевые данные и т. д. Например, для анализа запросов. , мы лишь собираем список используемых функций, время выполнения запроса, используемую память и некоторую другую метаинформацию. Мы никогда не собираем данные запроса или текст запроса.&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;p9qE&quot;&gt;Для этого мы разработали план получения данных из десятков источников, включая следующие.&lt;/p&gt;
  &lt;figure id=&quot;a2zx&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/38/e0/38e0a109-0b2a-4feb-97d3-a9961351b95b.png&quot; width=&quot;916&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;cch5&quot;&gt;Учитывая наши основные цели, мы сделали несколько предположений:&lt;/p&gt;
  &lt;ul id=&quot;DfTY&quot;&gt;
    &lt;li id=&quot;bAmC&quot;&gt;На нынешнем этапе достаточно детализации наших данных в один час. Это означает, что мы можем собирать и хранить агрегаты за каждый час.&lt;/li&gt;
    &lt;li id=&quot;ynx1&quot;&gt;На данный момент нам не нужно использовать подход CDC (или «сбор измененных данных»), поскольку он делает инфраструктуру СХД намного дороже. Традиционная прямая загрузка/ETL должна удовлетворить наши потребности. Если эти источники данных подлежат обновлению, мы можем выполнить полную перезагрузку данных.&lt;/li&gt;
    &lt;li id=&quot;7H35&quot;&gt;Поскольку у нас есть отличная масштабируемая и быстрая база данных, нам не нужно выполнять преобразования ETL за пределами базы данных. Вместо этого мы используем ClickHouse напрямую для выполнения преобразований с помощью SQL. Это прекрасно работает.&lt;/li&gt;
    &lt;li id=&quot;Lwco&quot;&gt;В ClickHouse мы по своей природе являемся открытым исходным кодом, поэтому мы хотим, чтобы весь наш стек содержал только компоненты с открытым исходным кодом. Мы также любим вносить свой вклад.&lt;/li&gt;
    &lt;li id=&quot;QYBA&quot;&gt;Поскольку у нас очень разные типы источников данных, нам понадобится несколько инструментов и подходов для извлечения данных из этих источников. В то же время нам необходимо стандартизированное промежуточное хранилище.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;Gh5T&quot;&gt;Однако одно из других наших первоначальных предположений оказалось неверным. Мы предполагали, что, поскольку наша структура данных не такая сложная, нам будет достаточно иметь в СХД всего два логических слоя — необработанный слой и слой «киоска данных». Это была ошибка. На самом деле нам нужен был третий промежуточный уровень, хранящий внутренние бизнес-объекты. Мы объясним это ниже.&lt;/p&gt;
  &lt;h2 id=&quot;architecture&quot;&gt;Архитектура&lt;/h2&gt;
  &lt;p id=&quot;S9xv&quot;&gt;В результате мы получили следующую архитектуру:&lt;/p&gt;
  &lt;figure id=&quot;ykYv&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/8a/22/8a226afc-802a-4c9d-91fb-2e78032822a9.png&quot; width=&quot;1459&quot; /&gt;
  &lt;/figure&gt;
  &lt;ol id=&quot;4JQj&quot;&gt;
    &lt;li id=&quot;812a&quot;&gt;На высоком уровне наш стек можно описать так:&lt;/li&gt;
    &lt;ul id=&quot;Ubi3&quot;&gt;
      &lt;li id=&quot;8eGw&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://clickhouse.cloud/signUp&quot; target=&quot;_blank&quot;&gt;ClickHouse Cloud&lt;/a&gt;&lt;/strong&gt; как основная база данных&lt;/li&gt;
      &lt;li id=&quot;ETeP&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://airflow.apache.org/&quot; target=&quot;_blank&quot;&gt;Airflow&lt;/a&gt;&lt;/strong&gt; как планировщик (инструмент планирования с открытым исходным кодом)&lt;/li&gt;
      &lt;li id=&quot;2tqd&quot;&gt;&lt;strong&gt;AWS S3&lt;/strong&gt; как промежуточное хранилище для данных RAW&lt;/li&gt;
      &lt;li id=&quot;PUW5&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://superset.apache.org/&quot; target=&quot;_blank&quot;&gt;Superset&lt;/a&gt;&lt;/strong&gt; как внутренний инструмент BI и AD-HOC&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;GHOx&quot;&gt;Мы используем различные инструменты и подходы для сбора данных из источников данных в несколько корзин S3:&lt;/li&gt;
    &lt;ul id=&quot;Ov58&quot;&gt;
      &lt;li id=&quot;rzlR&quot;&gt;Для плоскости управления, плоскости данных, сегмента и AWS CUR мы используем встроенные функции источника данных для экспорта данных.&lt;/li&gt;
      &lt;li id=&quot;nZA5&quot;&gt;Для выставления счетов GCP мы используем &lt;a href=&quot;https://cloud.google.com/bigquery/docs/reference/standard-sql/other-statements&quot; target=&quot;_blank&quot;&gt;экспортные запросы&lt;/a&gt; BigQuery для экспорта данных в GCS, откуда они могут быть получены &lt;a href=&quot;https://clickhouse.com/docs/en/sql-reference/table-functions/s3&quot; target=&quot;_blank&quot;&gt;табличной функцией ClickHouse S3.&lt;/a&gt;&lt;/li&gt;
      &lt;li id=&quot;QiBg&quot;&gt;Для Salesforce мы используем &lt;a href=&quot;https://docs.aws.amazon.com/appflow/latest/userguide/salesforce.html&quot; target=&quot;_blank&quot;&gt;AWS AppFlow.&lt;/a&gt;&lt;/li&gt;
      &lt;li id=&quot;kuC1&quot;&gt;Для захвата данных из M3ter мы написали собственное приложение. Изначально он был написан на Kotlin, позже мы перенесли его на Python.&lt;/li&gt;
      &lt;li id=&quot;x6wv&quot;&gt;Для Galaxy (который представлен кластером ClickHouse Cloud) мы используем &lt;a href=&quot;https://clickhouse.com/docs/en/sql-reference/table-functions/s3&quot; target=&quot;_blank&quot;&gt;табличную функцию ClickHouse S3&lt;/a&gt; для экспорта данных в S3.&lt;/li&gt;
      &lt;li id=&quot;LTwt&quot;&gt;Для Marketo мы используем &lt;a href=&quot;https://fivetran.com/docs/applications/marketo&quot; target=&quot;_blank&quot;&gt;Fivetran.&lt;/a&gt;&lt;/li&gt;
      &lt;li id=&quot;b8wc&quot;&gt;Наконец, поскольку цены AWS и GCP меняются очень редко, мы решили не автоматизировать их загрузку, а создали несколько скриптов, которые помогут нам вручную обновлять цены CSP при необходимости.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;ESgu&quot;&gt;Для больших таблиц фактов мы собираем почасовые приращения. Для словарей и таблиц, которые могут получать не только новые строки, но и обновления, мы используем подход «замены» (т.е. каждый час загружаем всю таблицу).&lt;/li&gt;
    &lt;li id=&quot;XAg4&quot;&gt;Как только почасовые данные собираются в корзине S3, мы используем &lt;a href=&quot;https://clickhouse.com/docs/en/sql-reference/table-functions/s3&quot; target=&quot;_blank&quot;&gt;табличную функцию ClickHouse s3&lt;/a&gt; для импорта данных в базу данных ClickHouse. Табличная функция S3 масштабируется по репликам и отлично работает с большими объемами данных.&lt;/li&gt;
    &lt;li id=&quot;SLwI&quot;&gt;Из корзины S3 данные вставляются в слой RAW в базе данных. Этот слой имеет ту же структуру таблицы, что и источники.&lt;/li&gt;
    &lt;li id=&quot;BJ2b&quot;&gt;После серии преобразований, выполняемых Airflow (включая соединения), данные из необработанных таблиц вставляются в таблицы MART — эти таблицы представляют бизнес-объекты и удовлетворяют потребности наших внутренних заинтересованных сторон.При выполнении преобразований используется множество временных таблиц. Фактически, большинство преобразованных результатов сначала записываются в промежуточную таблицу, а только потом вставляются в целевую таблицу. Хотя такой подход вносит некоторую сложность, он также дает нам необходимую гибкость повторного использования данных приращения. Это позволяет использовать одну часть приращения несколько раз без ее пересчета или повторного сканирования целевой таблицы. Промежуточные таблицы имеют уникальные имена для каждого запуска Airflow &lt;a href=&quot;https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/dags.html&quot; target=&quot;_blank&quot;&gt;DAG&lt;/a&gt; (направленные ациклические графы).&lt;/li&gt;
    &lt;li id=&quot;WRc6&quot;&gt;Наконец, инструмент Superset BI позволяет нашим внутренним пользователям запрашивать таблицы MART, а также строить диаграммы и информационные панели:&lt;/li&gt;
  &lt;/ol&gt;
  &lt;figure id=&quot;TPf6&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/75/54/7554dc12-515f-4915-8143-1f8326d1094e.png&quot; width=&quot;1600&quot; /&gt;
    &lt;figcaption&gt;Пример панели управления Superset. Примечание: в целях иллюстрации представлены примерные данные с поддельными номерами.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;nDw4&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;idempotency&quot;&gt;Идемпотентность&lt;/h3&gt;
  &lt;p id=&quot;UVNz&quot;&gt;Большинство таблиц, которые мы используем в ClickHouse, используют движки &lt;a href=&quot;https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replacingmergetree&quot; target=&quot;_blank&quot;&gt;ReplicationReplacingMergeTree&lt;/a&gt; . Этот движок позволяет нам не заботиться о дубликатах в таблицах — записи с одинаковым ключом будут удалены, и сохранится только последняя запись. Это также означает, что мы можем вставлять данные за один конкретный час столько раз, сколько потребуется — сохранится только одна последняя версия каждой строки. Мы также используем функцию ClickHouse « &lt;a href=&quot;https://clickhouse.com/docs/en/sql-reference/statements/select/from&quot; target=&quot;_blank&quot;&gt;FINAL&lt;/a&gt; », когда таблица используется в дальнейших преобразованиях для достижения согласованности, поэтому, например, функция &lt;code&gt;sum()&lt;/code&gt;не вычисляет строку дважды.&lt;/p&gt;
  &lt;p id=&quot;v5j9&quot;&gt;В сочетании с заданиями/DAG Airflow, которые допускают многократное выполнение в течение одного и того же периода, наш конвейер полностью идемпотентен и может безопасно выполняться повторно, не приводя к дублированию. Более подробная информация о конструкции внутреннего воздушного потока будет представлена ​​ниже.&lt;/p&gt;
  &lt;h3 id=&quot;consistency&quot;&gt;Последовательность&lt;/h3&gt;
  &lt;p id=&quot;lqP0&quot;&gt;По умолчанию ClickHouse обеспечивает итоговую согласованность. Это означает, что если вы успешно запустите запрос на вставку, это не гарантирует, что новые данные будут во всех репликах ClickHouse. Этого достаточно для аналитики в реальном времени, но неприемлемо для сценария СХД. Представьте, например, что вы вставляете данные в промежуточную таблицу. Вставка успешно завершается, и ваш процесс ELT начинает выполнять следующий запрос, который читает из промежуточной таблицы… и вы получаете только частичные данные.&lt;/p&gt;
  &lt;p id=&quot;VwEF&quot;&gt;Однако ClickHouse предлагает другой режим для случаев использования, когда согласованность важнее, чем мгновенная доступность вставленных данных на первом узле. Чтобы гарантировать, что запрос на вставку не вернет «успех», пока все реплики не получат данные, мы запускаем все запросы на вставку с настройкой &lt;code&gt;insert_quorum=3&lt;/code&gt;(у нас в кластере три узла). Мы не используем настройку «авто», потому что при выходе из строя одного узла (например, при выполнении обновления ClickHouse) два оставшихся узла все равно смогут принимать вставки. Как только перезапущенный узел станет доступен, вставленные данные в этом узле могут отсутствовать в течение некоторого времени. Поэтому для нас лучше получить ошибку ( &lt;code&gt;Number of alive replicas (2) is less than requested quorum (3/3).. (TOO_FEW_LIVE_REPLICAS&lt;/code&gt;) при вставке данных менее чем в три реплики. Поскольку перезапуски из-за обновлений происходят довольно быстро, запросы обычно завершаются успешно, если Airflow повторяет попытку после ошибки.&lt;/p&gt;
  &lt;p id=&quot;5rJd&quot;&gt;Конечно, такой подход не гарантирует, что незафиксированные части из предыдущих неудачных вставок не будут видны запросу, но это не проблема, поскольку мы поддерживаем идемпотентность, как описано в предыдущей части. Другим решением было бы запустить все процессы ELT, используя только одну реплику, но это может ограничить производительность.&lt;/p&gt;
  &lt;h3 id=&quot;internal-infrastructure-design&quot;&gt;Проектирование внутренней инфраструктуры&lt;/h3&gt;
  &lt;p id=&quot;3uoc&quot;&gt;Учитывая наш масштаб, нам нужно, чтобы наша инфраструктура СХД была простой, удобной в эксплуатации и легко масштабируемой. После запуска внутреннего PoC непосредственно на AWS EC2 мы перенесли все компоненты нашей инфраструктуры в Docker.&lt;/p&gt;
  &lt;figure id=&quot;UBDM&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0e/1c/0e1c27bf-ce66-491f-bfc0-f9580aabf6a5.png&quot; width=&quot;1470&quot; /&gt;
  &lt;/figure&gt;
  &lt;ul id=&quot;kJDU&quot;&gt;
    &lt;li id=&quot;xt5c&quot;&gt;У нас есть отдельные машины для веб-сервера Airflow, рабочего процесса Airflow и Superset. Все компоненты упакованы в Docker-контейнеры.&lt;/li&gt;
    &lt;li id=&quot;pN5x&quot;&gt;На машинах Airflow мы дополнительно каждые 5 секунд запускаем контейнер, который синхронизирует репозиторий, содержащий код наших DAG, запросы ELT и некоторые файлы конфигурации, с папкой, расположенной на машинах.&lt;/li&gt;
    &lt;li id=&quot;zBQY&quot;&gt;Мы используем панели мониторинга и функции оповещений Superset, поэтому у нас есть планировщик и рабочие контейнеры для Superset.&lt;/li&gt;
    &lt;li id=&quot;Egl4&quot;&gt;Все компоненты Airflow и Superset синхронизируются через экземпляр Redis, который работает на отдельной машине. Redis хранит состояние выполнения заданий и рабочий код для Airflow, кэшированные результаты запросов для Superset и некоторую другую служебную информацию.&lt;/li&gt;
    &lt;li id=&quot;J67j&quot;&gt;Мы используем AWS RDS для PostgreSQL в качестве внутренней базы данных для Airflow и Superset.&lt;/li&gt;
    &lt;li id=&quot;spyt&quot;&gt;У нас есть две среды, работающие независимо друг от друга с собственными экземплярами ClickHouse Cloud, Airflow и Superset, установленными в разных регионах.&lt;/li&gt;
    &lt;li id=&quot;MZk9&quot;&gt;Хотя одна среда называется Preprod, а другая — Prod, мы сохраняем целостность Preprod, чтобы иметь возможность переключиться, если Prod недоступен.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;89Pn&quot;&gt;Такая настройка позволяет нам безопасно и легко делать релизы:&lt;/p&gt;
  &lt;ol id=&quot;Odek&quot;&gt;
    &lt;li id=&quot;q7Ov&quot;&gt;Разработчик создает ветку из ветки разработки или производства.&lt;/li&gt;
    &lt;li id=&quot;6Bqj&quot;&gt;Разработчик вносит изменения&lt;/li&gt;
    &lt;li id=&quot;qD9i&quot;&gt;Разработчик создает PR в ветку Preprod&lt;/li&gt;
    &lt;li id=&quot;CXq7&quot;&gt;После рассмотрения и утверждения запроса на запрос изменения передаются в экземпляр Preprod Airflow, где они тестируются.&lt;/li&gt;
    &lt;li id=&quot;4Hr7&quot;&gt;Как только изменения будут готовы к выпуску в рабочую версию, выполняется PR из Preprod в ветку Prod.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h3 id=&quot;airflow-internal-design&quot;&gt;Внутренняя конструкция воздушного потока&lt;/h3&gt;
  &lt;p id=&quot;lbbC&quot;&gt;Изначально мы думали о создании сложной системы DAG со множеством зависимостей. К сожалению, ни один из существующих вариантов механики зависимостей DAG не может работать с нужной архитектурой (что является довольно распространенной проблемой в Airflow):&lt;/p&gt;
  &lt;ul id=&quot;32Fu&quot;&gt;
    &lt;li id=&quot;OH2v&quot;&gt;Airflow не позволяет именам наборов данных изменяться при выполнении. Поэтому &lt;a href=&quot;https://airflow.apache.org/docs/apache-airflow/stable/authoring-and-scheduling/datasets.html&quot; target=&quot;_blank&quot;&gt;недавно представленные наборы данных&lt;/a&gt; не могут использовать временные имена. Если мы используем статическое имя набора данных, нисходящий DAG будет запущен только один раз для последнего приращения.&lt;/li&gt;
    &lt;li id=&quot;M4Mu&quot;&gt;Триггеры могут работать на нас, но их использование слишком усложнит нашу настройку. Наличие 10–20 групп DAG с триггерами выглядит как кошмар зависимостей с операционной точки зрения.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;yNT8&quot;&gt;Таким образом, мы получили следующую структуру:&lt;/p&gt;
  &lt;ul id=&quot;XYEj&quot;&gt;
    &lt;li id=&quot;rFpZ&quot;&gt;Отдельные DAG для загрузки данных из источника данных в S3 (например, M3ter -&amp;gt; S3)&lt;/li&gt;
    &lt;li id=&quot;5LHH&quot;&gt;Одна огромная основная группа обеспечения доступности баз данных, которая выполняет все преобразования при доставке данных в S3.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;EamD&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;kspl&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e1/a9/e1a9bfca-adfb-4af6-8e9b-17b5b0a6c1c7.png&quot; width=&quot;1477&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;oYU3&quot;&gt;Основное преимущество такого подхода заключается в том, что он сочетает в себе наличие всех необходимых зависимостей, четко перечисленных в основных задачах группы обеспечения доступности баз данных, и возможность создавать сущности, не связанные с отказавшим набором данных.&lt;/p&gt;
  &lt;h3 id=&quot;security&quot;&gt;Безопасность&lt;/h3&gt;
  &lt;p id=&quot;yEDS&quot;&gt;Поскольку наша внутренняя система хранения данных хранит конфиденциальные данные, включая личные данные и финансовую информацию, безопасность должна быть основой нашей архитектуры. Для этого мы реализовали некоторые основные правила и набор схем работы с СХД.&lt;/p&gt;
  &lt;h4 id=&quot;general-rules&quot;&gt;Основные правила&lt;/h4&gt;
  &lt;ul id=&quot;dB0A&quot;&gt;
    &lt;li id=&quot;lQEn&quot;&gt;Разные данные должны быть доступны разным пользователям в соответствии с ролевой моделью компании, и это должно происходить автоматически.&lt;/li&gt;
    &lt;li id=&quot;bpIB&quot;&gt;Разделение разрешений должно выполняться на уровне &lt;strong&gt;базы данных&lt;/strong&gt; (не на стороне BI!)&lt;/li&gt;
    &lt;li id=&quot;74Pa&quot;&gt;Ограничения доступа к сети должны быть представлены на всех уровнях (от использования Okta для инструмента BI до IP-фильтрации).&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h4 id=&quot;implementation&quot;&gt;Выполнение&lt;/h4&gt;
  &lt;p id=&quot;Rj8Y&quot;&gt;Мы используем группы Google для контроля разрешений внутренних пользователей. Это позволяет нам использовать существующие внутренние группы компании, а также позволяет владельцам групп (которыми может быть нетехнический человек, не интересующийся SQL) контролировать доступ к различным данным. Группы могут быть вложенными. Например:&lt;/p&gt;
  &lt;ul id=&quot;0CJo&quot;&gt;
    &lt;li id=&quot;oBio&quot;&gt;&lt;a href=&quot;mailto:general_data@clickhouse.com&quot; target=&quot;_blank&quot;&gt;general_data@clickhouse.com&lt;/a&gt;&lt;/li&gt;
    &lt;ul id=&quot;rRbg&quot;&gt;
      &lt;li id=&quot;hwlI&quot;&gt;&lt;a href=&quot;mailto:company@clickhouse.com&quot; target=&quot;_blank&quot;&gt;company@clickhouse.com&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;vMva&quot;&gt;&lt;a href=&quot;mailto:financial_data@clickhouse.com&quot; target=&quot;_blank&quot;&gt;financial_data@clickhouse.com&lt;/a&gt;&lt;/li&gt;
    &lt;ul id=&quot;Tdhl&quot;&gt;
      &lt;li id=&quot;F4UV&quot;&gt;&lt;a href=&quot;mailto:thor@clickhouse.com&quot; target=&quot;_blank&quot;&gt;thor@clickhouse.com&lt;/a&gt;&lt;/li&gt;
      &lt;li id=&quot;kkgH&quot;&gt;&lt;a href=&quot;mailto:ironman@clickhouse.com&quot; target=&quot;_blank&quot;&gt;ironman@clickhouse.com&lt;/a&gt;&lt;/li&gt;
      &lt;li id=&quot;vWjK&quot;&gt;&lt;a href=&quot;mailto:thehulk@clickhouse.com&quot; target=&quot;_blank&quot;&gt;thehulk@clickhouse.com&lt;/a&gt;&lt;/li&gt;
      &lt;li id=&quot;O7EV&quot;&gt;&lt;a href=&quot;mailto:scrooge@clickhouse.com&quot; target=&quot;_blank&quot;&gt;scrooge@clickhouse.com&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;li id=&quot;g9Xg&quot;&gt;&lt;a href=&quot;mailto:hr_data@clickhouse.com&quot; target=&quot;_blank&quot;&gt;hr_data@clickhouse.com&lt;/a&gt;&lt;/li&gt;
    &lt;ul id=&quot;XdvQ&quot;&gt;
      &lt;li id=&quot;vprr&quot;&gt;&lt;a href=&quot;mailto:captain_clickhouse@clickhouse.com&quot; target=&quot;_blank&quot;&gt;captain_clickhouse@clickhouse.com&lt;/a&gt;&lt;/li&gt;
      &lt;li id=&quot;KbLY&quot;&gt;&lt;a href=&quot;mailto:chip@clickhouse.com&quot; target=&quot;_blank&quot;&gt;chip@clickhouse.com&lt;/a&gt;&lt;/li&gt;
      &lt;li id=&quot;13k0&quot;&gt;&lt;a href=&quot;mailto:superman@clickhouse.com&quot; target=&quot;_blank&quot;&gt;superman@clickhouse.com&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;0saH&quot;&gt;Для сопоставления групп Google с точными разрешениями мы используем системную таблицу, которая соединяет:&lt;/p&gt;
  &lt;ul id=&quot;NpYY&quot;&gt;
    &lt;li id=&quot;4TyC&quot;&gt;Название группы Google&lt;/li&gt;
    &lt;li id=&quot;TSoD&quot;&gt;Имя базы данных&lt;/li&gt;
    &lt;li id=&quot;dgim&quot;&gt;Имя таблицы&lt;/li&gt;
    &lt;li id=&quot;58hp&quot;&gt;Массив столбцов&lt;/li&gt;
    &lt;li id=&quot;uAJj&quot;&gt;Фильтр (например, «где организация=&amp;#x27;clickhouse&amp;#x27;»)&lt;/li&gt;
    &lt;li id=&quot;tCoa&quot;&gt;Тип доступа (ВЫБРАТЬ, ВСТАВИТЬ)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;mIGW&quot;&gt;У нас также есть скрипт, который делает следующее:&lt;/p&gt;
  &lt;ol id=&quot;EjBu&quot;&gt;
    &lt;li id=&quot;6qWj&quot;&gt;Получает рекурсивный список групп и пользователей.&lt;/li&gt;
    &lt;li id=&quot;K2Wz&quot;&gt;Создает (фактически заменяет) этих пользователей в базе данных с уникальным паролем.&lt;/li&gt;
    &lt;li id=&quot;2YLq&quot;&gt;Создает роли, соответствующие группам Google.&lt;/li&gt;
    &lt;li id=&quot;BKcr&quot;&gt;Назначает роли пользователям&lt;/li&gt;
    &lt;li id=&quot;Xm1V&quot;&gt;Предоставляет разрешения ролям в соответствии с таблицей разрешений с предложением «WITH REPLACE OPTION» — это удалит все остальные разрешения, которые по какой-то причине можно было сделать вручную.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;hv75&quot;&gt;На стороне Superset мы используем функцию &lt;a href=&quot;https://github.com/apache/superset/blob/b544993048583f77b2472bf4654b7abec7f8eaed/superset/config.py#L1042&quot; target=&quot;_blank&quot;&gt;DB_CONNECTION_MUTATOR&lt;/a&gt; для замены имени пользователя базы данных на пользователя Superset при отправке запроса в БД. У нас также включен Google Oauth в Superset. Это означает, что в DB_CONNECTION_MUTATOR у нас есть все необходимое для подключения Superset с нужным именем пользователя и паролем:&lt;/p&gt;
  &lt;pre id=&quot;zEEg&quot;&gt;def DB_CONNECTION_MUTATOR(uri, params, username, security_manager, source):
    # Only enable mutator on clickhouse cloud endpoints
    if not uri.host.lower().endswith(&amp;quot;clickhouse.cloud&amp;quot;):
        return uri, params
    user = security_manager.find_user(username=username)
    
    generated_username = str(user.email).split(&amp;#x27;@&amp;#x27;)[0] + &amp;#x27;--&amp;#x27; + str(user.username)
    uri.username = generated_username
    # Password generation logic - hidden in this example
    uri.password = ...
    return uri, params&lt;/pre&gt;
  &lt;p id=&quot;mhAi&quot;&gt;Вышеупомянутое означает, что Superset использует уникальное имя пользователя базы данных для каждого пользователя с уникальным набором разрешений, которые контролируются группами Google.&lt;/p&gt;
  &lt;h3 id=&quot;gdpr-compliance&quot;&gt;Соответствие GDPR&lt;/h3&gt;
  &lt;p id=&quot;rA3Z&quot;&gt;Пользователи ClickHouse Cloud могут попросить нас удалить все их личные данные, включая имя, адрес электронной почты и другую информацию. Разумеется, в этом случае мы также удаляем эту информацию из СХД. Самое крутое здесь то, что нам не нужно запускать какие-либо обновления или удаления в таблицах ClickHouse. Поскольку наш движок оставляет только одну последнюю запись для каждого значения ключа, все, что нам нужно сделать, это вставить новую версию строки с данными удаленных пользователей. Для исчезновения старых строк потребуется несколько часов, но стандарты GDPR дают вам от 3 до 30 дней на удаление данных в зависимости от сценария. Итак, полный алгоритм:&lt;/p&gt;
  &lt;ol id=&quot;4420&quot;&gt;
    &lt;li id=&quot;a4NX&quot;&gt;Найдите в одной из исходных систем специальный флаг, согласно которому этот идентификатор следует замаскировать/удалить.&lt;/li&gt;
    &lt;li id=&quot;IO83&quot;&gt;Выбрать все записи из таблицы с этим идентификатором&lt;/li&gt;
    &lt;li id=&quot;hjwV&quot;&gt;Маскировать обязательные поля&lt;/li&gt;
    &lt;li id=&quot;X9Yr&quot;&gt;Вставьте данные обратно в таблицу&lt;/li&gt;
    &lt;li id=&quot;1hoO&quot;&gt;Запустите команду «оптимизировать таблицу… окончательная», чтобы убедиться, что старые записи удалены с диска.&lt;/li&gt;
    &lt;li id=&quot;RonL&quot;&gt;Когда приходит новое почасовое приращение, мы выполняем объединение со списком удаленных идентификаторов. Это означает, что если по какой-либо причине информация PII пользователя еще не была полностью удалена, мы автоматически замаскируем эти данные.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;improvements-and-plans-for-future&quot;&gt;Улучшения и планы на будущее&lt;/h2&gt;
  &lt;p id=&quot;2ePk&quot;&gt;Хотя в целом мы удовлетворены нашей СХД, есть некоторые вещи, которые мы планируем изменить в ближайшие месяцы:&lt;/p&gt;
  &lt;h3 id=&quot;third-logical-layer&quot;&gt;Третий логический уровень&lt;/h3&gt;
  &lt;p id=&quot;jK1U&quot;&gt;Идея иметь только два логических слоя, к сожалению, не работает. Мы обнаружили, что для расчета действительно сложных метрик, которые можно заполнять обратно и которым нужны данные из более чем 5 источников данных, нам приходится создавать зависимости между различными витринами. Иногда это даже включает в себя рекурсивные зависимости. Чтобы решить эту проблему, нам нужно ввести промежуточный уровень, называемый хранилищем подробных данных или DDS. Он будет хранить некоторые внутренние бизнес-объекты, такие как учетная запись, организация, служба и т. д. Этот уровень не будет доступен для конечных пользователей, но он поможет нам удалить зависимости между витринами.&lt;/p&gt;
  &lt;h3 id=&quot;Rvs4&quot;&gt;DBT&lt;/h3&gt;
  &lt;p id=&quot;Alxg&quot;&gt;Airflow — хороший планировщик, но нам нужен инструмент, который позаботится о многих других вещах: при необходимости полная перезагрузка витрин данных, контроль качества, описание и документирование данных и другие. Для этого мы планируем интегрировать Airflow с DBT. Поскольку мы запускаем всю нашу инфраструктуру данных в контейнерах Docker, довольно легко создать отдельный контейнер DBT для наших нужд, который будет запускаться DAG Airflow.&lt;/p&gt;
  &lt;h3 id=&quot;naming-conventions&quot;&gt;Соглашения об именах&lt;/h3&gt;
  &lt;p id=&quot;jTMH&quot;&gt;Хотя с самого начала мы знали, что должны следовать некоторым правилам в именах таблиц, полей и диаграмм, мы не вложили в это слишком много ресурсов. В результате у нас теперь довольно запутанные имена, которые не позволяют пользователям понять назначение конкретной таблицы или поля. Нам нужно внести ясность.&lt;/p&gt;
  &lt;h2 id=&quot;resources&quot;&gt;Ресурсы&lt;/h2&gt;
  &lt;p id=&quot;7RGR&quot;&gt;ClickHouse — относительно молодая компания, поэтому наша команда DWH относительно небольшая и насчитывает всего 3 человека:&lt;/p&gt;
  &lt;ul id=&quot;oWZf&quot;&gt;
    &lt;li id=&quot;f9KX&quot;&gt;Data Engineer — строит и поддерживает инфраструктуру.&lt;/li&gt;
    &lt;li id=&quot;ybRt&quot;&gt;Аналитик продукта — помогает пользователям получать ценную информацию, строить диаграммы и понимать данные.&lt;/li&gt;
    &lt;li id=&quot;dZ9u&quot;&gt;Руководитель группы — тратит только ~30 % времени на задачи СХД.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;JY81&quot;&gt;Что касается инфраструктуры, мы используем две среды с отдельными сервисами ClickHouse Cloud. У каждого сервиса есть 3 узла (они же реплики, но все реплики принимают запросы). Использование памяти для наших сервисов ClickHouse составляет ~200 Гб. Хотя мы не платим за эти услуги, поскольку являемся частью команды ClickHouse Cloud, мы изучили цены и производительность конкурентов и полагаем, что другая облачная аналитическая база данных в нашем случае будет намного дороже.&lt;/p&gt;
  &lt;p id=&quot;xVkv&quot;&gt;Кроме того, наша инфраструктура включает в себя 8 машин EC2 и корзину S3 с необработанными данными. В общей сложности эти услуги стоят около ~$1500 в месяц.&lt;/p&gt;
  &lt;h2 id=&quot;overall-results&quot;&gt;Общие результаты&lt;/h2&gt;
  &lt;p id=&quot;UuKu&quot;&gt;Наша СХД работает уже не один год. У нас более 70 активных пользователей в месяц, сотни информационных панелей и тысячи диаграмм. Всего пользователи выполняют около 40 000 запросов в день. На этой диаграмме показано количество запросов в день с разбивкой по пользователям. Исключены пользователи системы и ELT:&lt;/p&gt;
  &lt;figure id=&quot;Aq2v&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/bd/28/bd283a98-4be9-401c-a004-2ae076c2bb97.png&quot; width=&quot;818&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;a9XE&quot;&gt;&lt;em&gt;Да, наши пользователи работают и по выходным.&lt;/em&gt;&lt;/p&gt;
  &lt;p id=&quot;oaU3&quot;&gt;Мы храним ~115 ТБ несжатых данных в ~150 таблицах, но из-за эффективного сжатия ClickHouse реальный размер хранимых данных составляет всего ~13 ТБ.&lt;/p&gt;
  &lt;figure id=&quot;93mW&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c9/18/c918b7cc-69cb-45ab-887a-343cd35e0db3.png&quot; width=&quot;1600&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;XgRN&quot;&gt;&lt;em&gt;Неделя за неделей растет объем данных в нашем СХД. Февральский всплеск представляет собой внутренний эксперимент, требующий дублирования всех данных.&lt;/em&gt;&lt;/p&gt;
  &lt;h2 id=&quot;summary&quot;&gt;Краткое содержание&lt;/h2&gt;
  &lt;p id=&quot;vxJG&quot;&gt;За год мы развернули СХД на основе технологии с открытым исходным кодом, которая обеспечивает удобство, которое нравится нашим пользователям. Хотя наш СХД упрощает работу с данными, мы также видим множество улучшений и изменений, которые нам необходимо внести, чтобы двигаться вперед. Мы считаем, что использование ClickHouse Cloud доказывает, что его можно использовать для создания надежного хранилища данных.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;hT1S&quot;&gt;Подписывайтесь на телеграм канал Apache Superset: &lt;a href=&quot;https://t.me/apache_superset_bi&quot; target=&quot;_blank&quot;&gt;https://t.me/apache_superset_bi&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>apache_superset:Customizing-Login-in-Apache-Superset-with-Token</id><link rel="alternate" type="text/html" href="https://teletype.in/@apache_superset/Customizing-Login-in-Apache-Superset-with-Token?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=apache_superset"></link><title>Enhancing Security and User Experience: Customizing Login in Apache Superset with Token</title><published>2023-06-29T10:39:17.488Z</published><updated>2023-06-29T10:44:03.757Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/c5/2f/c52f6b4d-3ed0-436d-9495-8ba0926d9f07.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:700/0*O5t1mgVu_DGPTMA6&quot;&gt;Source Article on Medium: https://medium.com/@mert1943992/enhancing-security-and-user-experience-customizing-login-in-apache-superset-with-token-204b95386b8a</summary><content type="html">
  &lt;figure id=&quot;4kTf&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://miro.medium.com/v2/resize:fit:700/0*O5t1mgVu_DGPTMA6&quot; width=&quot;700&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;da8d&quot;&gt;&lt;strong&gt;Source Article on Medium:&lt;/strong&gt; &lt;a href=&quot;https://medium.com/@mert1943992/enhancing-security-and-user-experience-customizing-login-in-apache-superset-with-token-204b95386b8a&quot; target=&quot;_blank&quot;&gt;https://medium.com/@mert1943992/enhancing-security-and-user-experience-customizing-login-in-apache-superset-with-token-204b95386b8a&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;W3KU&quot;&gt;&lt;strong&gt;What is Superset?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;5e32&quot;&gt;Apache Superset is an open-source business intelligence (BI) platform that allows users to easily explore and visualize data, build dashboards, and create interactive reports.&lt;/p&gt;
  &lt;p id=&quot;f64b&quot;&gt;With Superset, users can connect to various data sources, such as relational databases, NoSQL databases, cloud storage solutions, and more, to analyze and visualize data. It supports various visualization types, including bar charts, line charts, scatter plots, histograms, maps, and more. Users can also create custom charts using Python or SQL.&lt;/p&gt;
  &lt;p id=&quot;6667&quot;&gt;Superset also includes data exploration, SQL query generation, and data slicing and dicing. It has a user-friendly interface that allows users to quickly drag and drop data to create interactive dashboards and reports.&lt;/p&gt;
  &lt;p id=&quot;6034&quot;&gt;Superset is highly customizable and can be extended through custom plugins and integrations. It also supports integration with popular authentication providers and supports role-based access control for data and dashboard sharing.&lt;/p&gt;
  &lt;figure id=&quot;69XW&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f5/00/f500f04a-5552-4882-ba90-197f13c21d7f.jpeg&quot; width=&quot;700&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;b770&quot;&gt;&lt;strong&gt;Customize Config&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;3709&quot;&gt;To customize the configuration of Apache Superset, you can modify its configuration files to tailor the behavior and appearance of the application. By adding the volume to run the command you can customize the config file. In the &lt;em&gt;superset_config.py&lt;/em&gt;, the below definitions are added to override login methods.&lt;/p&gt;
  &lt;pre id=&quot;8yDP&quot;&gt;# other configs
from custom_security import CustomSecurityManager
CUSTOM_SECURITY_MANAGER = CustomSecurityManager
# other configs&lt;/pre&gt;
  &lt;p id=&quot;9866&quot;&gt;&lt;strong&gt;Example Project&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;36ed&quot;&gt;To better understand, an example project is explained. For redirect assuming that the token is generated from another project. The token should write into a database. An example table can have columns like below.&lt;/p&gt;
  &lt;figure id=&quot;71cS&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1f/b6/1fb68f73-0ebb-401f-b462-1248eb63c081.webp&quot; width=&quot;317&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;cf59&quot;&gt;The main project should insert a token before redirecting the user to the Apache superset. The consumed column should be &lt;em&gt;false &lt;/em&gt;in the insertion to prevent second use.&lt;/p&gt;
  &lt;p id=&quot;dc1c&quot;&gt;&lt;strong&gt;Custom Security&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;749f&quot;&gt;Apache Superset supports integration with external authentication and authorization providers. Users can customize the authentication and authorization logic to meet their specific requirements. For creating a custom login custom_security.py file was created. In the example, the Oracle database is used.&lt;/p&gt;
  &lt;pre id=&quot;CX1N&quot;&gt;from flask import redirect, g, flash, request
from flask_appbuilder.security.views import UserDBModelView, AuthDBView
from superset.security import SupersetSecurityManager
from flask_appbuilder.security.views import expose
from flask_appbuilder.security.manager import BaseSecurityManager
from flask_login import login_user, logout_user
from datetime import datetime
import cx_Oracle

class SupersetAuth:
    def __init__(self, id, token, username, consumed, creationDate, expirationDate, consumedDate, userId):
        self.id = id
        self.token = token
        self.username = username
        self.consumed = consumed
        self.creationDate = creationDate
        self.expirationDate = expirationDate
        self.consumedDate = consumedDate
        self.userId = userId


class CustomAuthDBView(AuthDBView):
    login_template = &amp;#x27;appbuilder/general/security/login_db.html&amp;#x27;

    @expose(&amp;#x27;/login/&amp;#x27;, methods=[&amp;#x27;GET&amp;#x27;, &amp;#x27;POST&amp;#x27;])
    def login(self):
        authsuccess = False
        usernameFromPath = &amp;#x27;&amp;#x27;
        token = &amp;#x27;&amp;#x27;
        redirect_url = self.appbuilder.get_url_for_index

        if request.args.get(&amp;#x27;redirect&amp;#x27;) is not None:
            redirect_url = request.args.get(&amp;#x27;redirect&amp;#x27;)
        if request.args.get(&amp;#x27;username&amp;#x27;) is not None:
            usernameFromPath = request.args.get(&amp;#x27;username&amp;#x27;)
            user = self.appbuilder.sm.find_user(username=usernameFromPath)
        if request.args.get(&amp;#x27;token&amp;#x27;) is not None:
            token = request.args.get(&amp;#x27;token&amp;#x27;)

        if usernameFromPath != &amp;#x27;&amp;#x27;:
            try:
                connection = cx_Oracle.connect(&amp;#x27;username&amp;#x27;, &amp;#x27;password&amp;#x27;, &amp;#x27;host:port/schema&amp;#x27;, encoding=&amp;quot;UTF-8&amp;quot;)
                connection.autocommit = True
                cursor = connection.cursor()
                cursor.execute(&amp;#x27;select * from superset_auth where token=:tokenToDb&amp;#x27;, tokenToDb=token)
                fromDb = cursor.fetchone()
                if fromDb:
                    supersetAuth = SupersetAuth(*fromDb)
                    today = datetime.today()
                    if supersetAuth.consumed == 1:
                        flash(&amp;#x27;InvalidToken&amp;#x27;, &amp;#x27;warning&amp;#x27;)
                        return super().login()
                    if supersetAuth.expirationDate &amp;gt; today and supersetAuth.username == usernameFromPath:
                        statement = &amp;quot;update superset_auth set consumed=:consumed, consumed_time=:consumedTime where id=:id&amp;quot;
                        cursor.execute(statement, {&amp;#x27;consumed&amp;#x27;: True, &amp;#x27;consumedTime&amp;#x27;: today, &amp;#x27;id&amp;#x27;: supersetAuth.id})
                        authsuccess = True
            except cx_Oracle.Error as error:
                print(error)
            finally:
                if connection:
                    cursor.close()
                    connection.close()

        if g.user is not None and g.user.is_authenticated and not authsuccess:
            return redirect(redirect_url)

        if authsuccess:
            login_user(user, remember=False)
            return redirect(redirect_url)
        else:
            flash(&amp;#x27;Auto Login Failed&amp;#x27;, &amp;#x27;warning&amp;#x27;)
            return super().login()


class CustomSecurityManager(SupersetSecurityManager):
    authdbview = CustomAuthDBView

    def __init__(self, appbuilder):
        super().__init__(appbuilder)&lt;/pre&gt;
  &lt;p id=&quot;c52b&quot;&gt;&lt;strong&gt;Installation of Superset&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;cdef&quot;&gt;Assuming that&lt;em&gt; custom_security.py&lt;/em&gt; and &lt;em&gt;superset_config.py&lt;/em&gt; are located in &lt;em&gt;/DATA/etc/superset&lt;/em&gt; in your machine.&lt;/p&gt;
  &lt;pre id=&quot;AieV&quot;&gt;docker run - detach -v DATA/etc/superset:/etc/superset –name superset -p 8088:8088 amancevice/superset&lt;/pre&gt;
  &lt;p id=&quot;eec4&quot;&gt;This command creates a Docker container named “superset” and maps the container’s port 8088 to the host machine’s port 8088, which is the default port used by Superset. You can use a different port number if needed.&lt;/p&gt;
  &lt;p id=&quot;20c3&quot;&gt;To start superset enter the container and run the below commands on bash.&lt;/p&gt;
  &lt;pre id=&quot;xa0m&quot;&gt;docker exec -it superset /bin/bash
superset fab create-admin --username admin --firstname admin --lastname admin --email admin@testmail.com --password Admin1234!
superset db upgrade
superset load_examples
superset init&lt;/pre&gt;
  &lt;p id=&quot;d540&quot;&gt;Your superset will be ready to use in a little while.&lt;/p&gt;
  &lt;p id=&quot;8cf3&quot;&gt;&lt;strong&gt;Usage of Custom Login&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;4f60&quot;&gt;After the token is generated, url should be like this.&lt;br /&gt;&lt;a href=&quot;http://host:port/login?username=username&amp;token=token&quot; target=&quot;_blank&quot;&gt;http://host:port/login?username=&lt;em&gt;username&lt;/em&gt;&amp;amp;token=&lt;em&gt;token&lt;/em&gt;&lt;/a&gt;&lt;em&gt;S&lt;/em&gt;uperset will automatically log the user into the system and inform the database that the token has been used.&lt;br /&gt;You can also log in to the system with a Username and Password.&lt;/p&gt;
  &lt;p id=&quot;c464&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;dd8c&quot;&gt;Superset is an advanced data visualization tool and is preferred by many people and institutions because it is free. When integrating the superset into existing UI projects, it may be necessary to customize the login methods. In the example we gave in this article, we have seen how to log in to the system automatically using Tokens. By changing the rewritten config file, it can be provided to serve different scenarios.&lt;/p&gt;

</content></entry><entry><id>apache_superset:how-create-user-via-keycloak-with-public-role</id><link rel="alternate" type="text/html" href="https://teletype.in/@apache_superset/how-create-user-via-keycloak-with-public-role?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=apache_superset"></link><title>Как создать пользователя при авторизации через keycloak в Apache Superset</title><published>2022-08-26T11:20:46.300Z</published><updated>2022-08-26T11:21:41.831Z</updated><summary type="html">В данном примере приведен скрипт из config файла, который автоматически создает пользователя при авторизации через keycloak. Кейс не полный, это лишь отрывок кода, но возможно кому-то поможет.</summary><content type="html">
  &lt;h2 id=&quot;tPtY&quot;&gt;Автоматическое создание пользователя&lt;/h2&gt;
  &lt;p id=&quot;PFRv&quot;&gt;В данном примере приведен скрипт из config файла, который автоматически создает пользователя при авторизации через keycloak. Кейс не полный, это лишь отрывок кода, но возможно кому-то поможет.&lt;/p&gt;
  &lt;pre id=&quot;nnzO&quot;&gt;configOverrides:
  enable_remote_user: |
    from flask_appbuilder.security.manager import AUTH_REMOTE_USER
    from superset.security import SupersetSecurityManager
    from flask import redirect, g, flash, request, session
    from flask_appbuilder._compat import as_unicode
    from flask_appbuilder.security.views import expose, AuthRemoteUserView
    from flask_appbuilder.security.forms import LoginForm_db
    from flask_login import login_user

    class CustomRemoteUserView(AuthRemoteUserView):
        login_template = &amp;quot;appbuilder/general/security/login_db.html&amp;quot;

        @expose(&amp;#x27;/login/&amp;#x27;, methods=[&amp;quot;GET&amp;quot;, &amp;quot;POST&amp;quot;])
        def login(self):
            if g.user is not None and g.user.is_authenticated:
                return redirect(self.appbuilder.get_url_for_index)

            username = request.headers.get(&amp;#x27;X-Auth-Username&amp;#x27;, None)
            if username:
                user = self.appbuilder.sm.auth_user_remote_user(username)
                if user is None:
                    first_name = request.headers.get(&amp;#x27;X-Auth-Given-Name&amp;#x27;, &amp;#x27;&amp;#x27;)
                    last_name = request.headers.get(&amp;#x27;X-Auth-Family-Name&amp;#x27;, &amp;#x27;&amp;#x27;)
                    email = username
                    user_role = self.appbuilder.sm.find_role(AUTH_NEW_USER_ROLE)
                    user = self.appbuilder.sm.add_user(username, first_name, last_name, email, user_role)

                login_user(user)
                return redirect(self.appbuilder.get_url_for_index)
            else:
                form = LoginForm_db()
                if form.validate_on_submit():
                    user = self.appbuilder.sm.auth_user_db(
                        form.username.data, form.password.data
                    )
                    if not user:
                        flash(as_unicode(self.invalid_login_message), &amp;#x27;warning&amp;#x27;)
                        return redirect(self.appbuilder.get_url_for_login)
                    login_user(user, remember=False)
                    return redirect(self.appbuilder.get_url_for_index)
                return self.render_template(
                    self.login_template, title=self.title, form=form, appbuilder=self.appbuilder
                )

    class CustomSecurityManager(SupersetSecurityManager):
        authremoteuserview = CustomRemoteUserView

    ENABLE_PROXY_FIX = True
    AUTH_TYPE = AUTH_REMOTE_USER
    CUSTOM_SECURITY_MANAGER = CustomSecurityManager
    AUTH_USER_REGISTRATION = False
    AUTH_NEW_USER_ROLE = &amp;#x27;Public&amp;#x27;

    # Workaround as defult config from chart not set redis password for celery brokers
    class CustomCeleryConfig(object):
      BROKER_URL = f&amp;quot;redis://:{env(&amp;#x27;REDIS_PASSWORD&amp;#x27;)}@{env(&amp;#x27;REDIS_HOST&amp;#x27;)}:{env(&amp;#x27;REDIS_PORT&amp;#x27;)}/0&amp;quot;
      CELERY_IMPORTS = (&amp;#x27;superset.sql_lab&amp;#x27;, )
      CELERY_RESULT_BACKEND = f&amp;quot;redis://:{env(&amp;#x27;REDIS_PASSWORD&amp;#x27;)}@{env(&amp;#x27;REDIS_HOST&amp;#x27;)}:{env(&amp;#x27;REDIS_PORT&amp;#x27;)}/0&amp;quot;
      CELERY_ANNOTATIONS = {&amp;#x27;tasks.add&amp;#x27;: {&amp;#x27;rate_limit&amp;#x27;: &amp;#x27;10/s&amp;#x27;}}

    CELERY_CONFIG = CustomCeleryConfig
    RESULTS_BACKEND = RedisCache(
          host=env(&amp;#x27;REDIS_HOST&amp;#x27;),
          port=env(&amp;#x27;REDIS_PORT&amp;#x27;),
          password=env(&amp;#x27;REDIS_PASSWORD&amp;#x27;),
          key_prefix=&amp;#x27;superset_results&amp;#x27;
    )&lt;/pre&gt;
  &lt;h2 id=&quot;maxe&quot;&gt;Using OpenIDKeycloak with Superset&lt;/h2&gt;
  &lt;p id=&quot;bjGI&quot;&gt;&lt;a href=&quot;https://www.anycodings.com/1questions/1028410/using-openidkeycloak-with-superset&quot; target=&quot;_blank&quot;&gt;https://www.anycodings.com/1questions/1028410/using-openidkeycloak-with-superset&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;lIec&quot;&gt;Если вдруг статья не откроется - ниже копия.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;B5fl&quot;&gt;&lt;strong&gt; Questions : &lt;/strong&gt;Using OpenIDKeycloak with Superset&lt;/h2&gt;
  &lt;p id=&quot;vWgi&quot;&gt;I want to use keycloak to authenticate my anycodings_apache-superset  users in our Superset environment.&lt;/p&gt;
  &lt;p id=&quot;yOz6&quot;&gt;Superset is using flask-openid, as anycodings_apache-superset  implemented in flask-security:&lt;/p&gt;
  &lt;ul id=&quot;D7Uh&quot;&gt;
    &lt;li id=&quot;emu7&quot;&gt;&lt;a href=&quot;http://flask-appbuilder.readthedocs.io/en/latest/_modules/flask_appbuilder/security/manager.html&quot; target=&quot;_blank&quot;&gt;http://flask-appbuilder.readthedocs.io/en/latest/_modules/flask_appbuilder/security/manager.html&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;gopg&quot;&gt;&lt;a href=&quot;https://pythonhosted.org/Flask-OpenID/&quot; target=&quot;_blank&quot;&gt;https://pythonhosted.org/Flask-OpenID/&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;wWqG&quot;&gt;To enable a different user authentication anycodings_apache-superset  than the regular one (database), you need to anycodings_apache-superset  override the AUTH_TYPE parameter in your anycodings_apache-superset  superset_config.py file. You will also need anycodings_apache-superset  to provide a reference to your anycodings_apache-superset  openid-connect realm and enable user anycodings_apache-superset  registration. As I understand, it should anycodings_apache-superset  look something like this:&lt;/p&gt;
  &lt;pre id=&quot;MWXK&quot;&gt;from flask_appbuilder.security.manager import AUTH_OID
AUTH_TYPE = AUTH_OID
OPENID_PROVIDERS = [
    { &amp;#x27;name&amp;#x27;:&amp;#x27;keycloak&amp;#x27;, &amp;#x27;url&amp;#x27;:&amp;#x27;http://localhost:8080/auth/realms/superset&amp;#x27; }
]
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = &amp;#x27;Gamma&amp;#x27;
&lt;/pre&gt;
  &lt;p id=&quot;oK8v&quot;&gt;With this configuration, the login page anycodings_apache-superset  changes to a prompt where the user can anycodings_apache-superset  select the desired OpenID provider (in our anycodings_apache-superset  case keycloak). We also have two buttons, anycodings_apache-superset  one to sign in (for existing users) and one anycodings_apache-superset  to register as a new user.&lt;/p&gt;
  &lt;p id=&quot;CkiP&quot;&gt;I would expect that either of these buttons anycodings_apache-superset  would take me to my keycloak login page. anycodings_apache-superset  However, this does not happen. Instead, I am anycodings_apache-superset  redirected right back to the login page.&lt;/p&gt;
  &lt;p id=&quot;d1or&quot;&gt;In the case where I press the registration anycodings_apache-superset  button, I get a message that says &amp;#x27;Not anycodings_apache-superset  possible to register you at the moment, try anycodings_apache-superset  again later&amp;#x27;. When I press the sign in anycodings_apache-superset  button, no message is displayed. The anycodings_apache-superset  Superset logs show the request that loads anycodings_apache-superset  the login page, but no requests to keycloak. anycodings_apache-superset  I have tried the same using the Google anycodings_apache-superset  OpenID provider, which works just fine.&lt;/p&gt;
  &lt;p id=&quot;iHER&quot;&gt;Since I am seeing no requests to keycloak, anycodings_apache-superset  this makes me think that I am either missing anycodings_apache-superset  a configuration setting somewhere, or that I anycodings_apache-superset  am using the wrong settings. Could you anycodings_apache-superset  please help me figure out which settings I anycodings_apache-superset  should be using?&lt;/p&gt;
  &lt;p id=&quot;9FHu&quot;&gt;&lt;a href=&quot;https://www.anycodings.com/search?q=python&quot; target=&quot;_blank&quot;&gt;PYTHON&lt;/a&gt;&lt;a href=&quot;https://www.anycodings.com/search?q=openid-connect&quot; target=&quot;_blank&quot;&gt;OPENID-CONNECT&lt;/a&gt;&lt;a href=&quot;https://www.anycodings.com/search?q=keycloak&quot; target=&quot;_blank&quot;&gt;KEYCLOAK&lt;/a&gt;&lt;a href=&quot;https://www.anycodings.com/search?q=flask-security&quot; target=&quot;_blank&quot;&gt;FLASK-SECURITY&lt;/a&gt;&lt;a href=&quot;https://www.anycodings.com/search?q=apache-superset&quot; target=&quot;_blank&quot;&gt;APACHE-SUPERSET&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;ZKhA&quot;&gt;Total Answers &lt;strong&gt;3&lt;/strong&gt;&lt;/p&gt;
  &lt;h2 id=&quot;tT2f&quot;&gt;&lt;strong&gt;Answers 1 :&lt;/strong&gt; of Using OpenIDKeycloak with Superset&lt;/h2&gt;
  &lt;h3 id=&quot;GVaU&quot;&gt;Update 03-02-2020&lt;/h3&gt;
  &lt;p id=&quot;MxVd&quot;&gt;@s.j.meyer has written an updated guide anycodings_python  which works with Superset 0.28.1 and up. anycodings_python  I haven&amp;#x27;t tried it myself, but thanks anycodings_python  @nawazxy for confirming this solution anycodings_python  works.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;NTvN&quot;&gt;I managed to solve my own question. The anycodings_python  main problem was caused by a wrong anycodings_python  assumption I made regarding the anycodings_python  flask-openid plugin that superset is anycodings_python  using. This plugin actually supports anycodings_python  OpenID 2.x, but not OpenID-Connect anycodings_python  (which is the version implemented by anycodings_python  Keycloak).&lt;/p&gt;
  &lt;p id=&quot;PUw5&quot;&gt;As a workaround, I decided to switch to anycodings_python  the flask-oidc plugin. Switching to a anycodings_python  new authentication provider actually anycodings_python  requires some digging work. To integrate anycodings_python  the plugin, I had to follow these steps:&lt;/p&gt;
  &lt;h3 id=&quot;k6rB&quot;&gt;Configue flask-oidc for keycloak&lt;/h3&gt;
  &lt;p id=&quot;9Hby&quot;&gt;Unfortunately, flask-oidc does not anycodings_python  support the configuration format anycodings_python  generated by Keycloak. Instead, your anycodings_python  configuration should look something like anycodings_python  this:&lt;/p&gt;
  &lt;pre id=&quot;D1pK&quot;&gt;{
    &amp;quot;web&amp;quot;: {
        &amp;quot;realm_public_key&amp;quot;: &amp;quot;&amp;lt;YOUR_REALM_PUBLIC_KEY&amp;gt;&amp;quot;,
        &amp;quot;issuer&amp;quot;: &amp;quot;http://&amp;lt;YOUR_DOMAIN&amp;gt;/auth/realms/&amp;lt;YOUR_REALM_ID&amp;gt;&amp;quot;,
        &amp;quot;auth_uri&amp;quot;: &amp;quot;http://&amp;lt;YOUR_DOMAIN&amp;gt;/auth/realms/&amp;lt;YOUR_REALM_ID&amp;gt;/protocol/openid-connect/auth&amp;quot;,
        &amp;quot;client_id&amp;quot;: &amp;quot;&amp;lt;YOUR_CLIENT_ID&amp;gt;&amp;quot;,
        &amp;quot;client_secret&amp;quot;: &amp;quot;&amp;lt;YOUR_SECRET_KEY&amp;gt;&amp;quot;,
        &amp;quot;redirect_urls&amp;quot;: [
            &amp;quot;http://&amp;lt;YOUR_DOMAIN&amp;gt;/*&amp;quot;
        ],
        &amp;quot;userinfo_uri&amp;quot;: &amp;quot;http://&amp;lt;YOUR_DOMAIN&amp;gt;/auth/realms/&amp;lt;YOUR_REALM_ID&amp;gt;/protocol/openid-connect/userinfo&amp;quot;,
        &amp;quot;token_uri&amp;quot;: &amp;quot;http://&amp;lt;YOUR_DOMAIN&amp;gt;/auth/realms/&amp;lt;YOUR_REALM_ID&amp;gt;/protocol/openid-connect/token&amp;quot;,
        &amp;quot;token_introspection_uri&amp;quot;: &amp;quot;http://&amp;lt;YOUR_DOMAIN&amp;gt;/auth/realms/&amp;lt;YOUR_REALM_ID&amp;gt;/protocol/openid-connect/token/introspect&amp;quot;
    }
}
&lt;/pre&gt;
  &lt;p id=&quot;PbUM&quot;&gt;Flask-oidc expects the configuration to anycodings_python  be in a file. I have stored mine in anycodings_python  client_secret.json. You can configure anycodings_python  the path to the configuration file in anycodings_python  your superset_config.py.&lt;/p&gt;
  &lt;h3 id=&quot;QZyC&quot;&gt;Extend the Security Manager&lt;/h3&gt;
  &lt;p id=&quot;Kzsq&quot;&gt;Firstly, you will want to make sure that anycodings_python  flask stops using flask-openid ad starts anycodings_python  using flask-oidc instead. To do so, you anycodings_python  will need to create your own security anycodings_python  manager that configures flask-oidc as anycodings_python  its authentication provider. I have anycodings_python  implemented my security manager like anycodings_python  this:&lt;/p&gt;
  &lt;pre id=&quot;Y1BR&quot;&gt;from flask_appbuilder.security.manager import AUTH_OID
from flask_appbuilder.security.sqla.manager import SecurityManager
from flask_oidc import OpenIDConnect
    
class OIDCSecurityManager(SecurityManager):

def __init__(self,appbuilder):
    super(OIDCSecurityManager, self).__init__(appbuilder)
    if self.auth_type == AUTH_OID:
        self.oid = OpenIDConnect(self.appbuilder.get_app)
    self.authoidview = AuthOIDCView
&lt;/pre&gt;
  &lt;p id=&quot;XVb4&quot;&gt;To enable OpenID in Superset, you would anycodings_python  previously have had to set the anycodings_python  authentication type to AUTH_OID. My anycodings_python  security manager still executes all the anycodings_python  behaviour of the super class, but anycodings_python  overrides the oid attribute with the anycodings_python  OpenIDConnect object. Further, it anycodings_python  replaces the default OpenID anycodings_python  authentication view with a custom one. I anycodings_python  have implemented mine like this:&lt;/p&gt;
  &lt;pre id=&quot;53Kj&quot;&gt;from flask_appbuilder.security.views import AuthOIDView
from flask_login import login_user
from urllib import quote

class AuthOIDCView(AuthOIDView):

@expose(&amp;#x27;/login/&amp;#x27;, methods=[&amp;#x27;GET&amp;#x27;, &amp;#x27;POST&amp;#x27;])
def login(self, flag=True):
    
    sm = self.appbuilder.sm
    oidc = sm.oid

    @self.appbuilder.sm.oid.require_login
    def handle_login(): 
        user = sm.auth_user_oid(oidc.user_getfield(&amp;#x27;email&amp;#x27;))
        
        if user is None:
            info = oidc.user_getinfo([&amp;#x27;preferred_username&amp;#x27;, &amp;#x27;given_name&amp;#x27;, &amp;#x27;family_name&amp;#x27;, &amp;#x27;email&amp;#x27;])
            user = sm.add_user(info.get(&amp;#x27;preferred_username&amp;#x27;), info.get(&amp;#x27;given_name&amp;#x27;), info.get(&amp;#x27;family_name&amp;#x27;), info.get(&amp;#x27;email&amp;#x27;), sm.find_role(&amp;#x27;Gamma&amp;#x27;)) 
        
        login_user(user, remember=False)
        return redirect(self.appbuilder.get_url_for_index)  
   
return handle_login()  

@expose(&amp;#x27;/logout/&amp;#x27;, methods=[&amp;#x27;GET&amp;#x27;, &amp;#x27;POST&amp;#x27;])
def logout(self):
    
    oidc = self.appbuilder.sm.oid
    
    oidc.logout()
    super(AuthOIDCView, self).logout()        
    redirect_url = request.url_root.strip(&amp;#x27;/&amp;#x27;) + self.appbuilder.get_url_for_login
    
    return redirect(oidc.client_secrets.get(&amp;#x27;issuer&amp;#x27;) + &amp;#x27;/protocol/openid-connect/logout?redirect_uri=&amp;#x27; + quote(redirect_url))
&lt;/pre&gt;
  &lt;p id=&quot;fknW&quot;&gt;My view overrides the behaviours at the anycodings_python  /login and /logout endpoints. On login, anycodings_python  the handle_login method is run. It anycodings_python  requires the user to be authenticated by anycodings_python  the OIDC provider. In our case, this anycodings_python  means the user will first be redirected anycodings_python  to Keycloak to log in.&lt;/p&gt;
  &lt;p id=&quot;SNFM&quot;&gt;On authentication, the user is anycodings_python  redirected back to Superset. Next, we anycodings_python  look up whether we recognize the user. anycodings_python  If not, we create the user based on anycodings_python  their OIDC user info. Finally, we log anycodings_python  the user into Superset and redirect them anycodings_python  to the landing page.&lt;/p&gt;
  &lt;p id=&quot;EXWy&quot;&gt;On logout, we will need to invalidate anycodings_python  these cookies:&lt;/p&gt;
  &lt;ol id=&quot;owNB&quot;&gt;
    &lt;li id=&quot;hyBx&quot;&gt;The superset session&lt;/li&gt;
    &lt;li id=&quot;c2JS&quot;&gt;The OIDC token&lt;/li&gt;
    &lt;li id=&quot;vjcb&quot;&gt;The cookies set by Keycloak&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;doyu&quot;&gt;By default, Superset will only take care anycodings_python  of the first. The extended logout method anycodings_python  takes care of all three points.&lt;/p&gt;
  &lt;h3 id=&quot;LIdX&quot;&gt;Configure Superset&lt;/h3&gt;
  &lt;p id=&quot;q0RQ&quot;&gt;Finally, we need to add some parameters anycodings_python  to our superset_config.py. This is how anycodings_python  I&amp;#x27;ve configured mine:&lt;/p&gt;
  &lt;pre id=&quot;i8mp&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
AUTHENTICATION
&amp;#x27;&amp;#x27;&amp;#x27;
AUTH_TYPE = AUTH_OID
OIDC_CLIENT_SECRETS = &amp;#x27;client_secret.json&amp;#x27;
OIDC_ID_TOKEN_COOKIE_SECURE = False
OIDC_REQUIRE_VERIFIED_EMAIL = False
CUSTOM_SECURITY_MANAGER = OIDCSecurityManager
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = &amp;#x27;Gamma&amp;#x27;
&lt;/pre&gt;
  &lt;p id=&quot;0MXm&quot;&gt;0&lt;/p&gt;
  &lt;h2 id=&quot;PCPV&quot;&gt;&lt;strong&gt;Answers 2 :&lt;/strong&gt; of Using OpenIDKeycloak with Superset&lt;/h2&gt;
  &lt;p id=&quot;dqfX&quot;&gt;I had some trouble with the OIDC anycodings_python  library, so I configured it a bit anycodings_python  differently -&lt;/p&gt;
  &lt;p id=&quot;l1Jv&quot;&gt;In Keycloak, I created a new client with anycodings_python  standard flow and confidential access. I anycodings_python  also added a roles token claim in the anycodings_python  mapper, so I could map &amp;quot;Client Roles&amp;quot; to anycodings_python  Superset Roles.&lt;/p&gt;
  &lt;p id=&quot;0bsS&quot;&gt;For Superset, I mount the custom anycodings_python  configuration files to my container [k8s anycodings_python  in my case].&lt;/p&gt;
  &lt;p id=&quot;zCKC&quot;&gt;/app/pythonpath/custom_sso_security_manager.py&lt;/p&gt;
  &lt;pre id=&quot;VEka&quot;&gt;import logging
import os
import json
from superset.security import SupersetSecurityManager


logger = logging.getLogger(&amp;#x27;oauth_login&amp;#x27;)

class CustomSsoSecurityManager(SupersetSecurityManager):

    def oauth_user_info(self, provider, response=None):
        logging.debug(&amp;quot;Oauth2 provider: {0}.&amp;quot;.format(provider))

        logging.debug(&amp;quot;Oauth2 oauth_remotes provider: {0}.&amp;quot;.format(self.appbuilder.sm.oauth_remotes[provider]))

        if provider == &amp;#x27;keycloak&amp;#x27;:
            # Get the user info using the access token
            res = self.appbuilder.sm.oauth_remotes[provider].get(os.getenv(&amp;#x27;KEYCLOAK_BASE_URL&amp;#x27;) + &amp;#x27;/userinfo&amp;#x27;)

            logger.info(f&amp;quot;userinfo response:&amp;quot;)
            for attr, value in vars(res).items():
                print(attr, &amp;#x27;=&amp;#x27;, value)

            if res.status_code != 200:
                logger.error(&amp;#x27;Failed to obtain user info: %s&amp;#x27;, res._content)
                return

            #dict_str = res._content.decode(&amp;quot;UTF-8&amp;quot;)
            me = json.loads(res._content)

            logger.debug(&amp;quot; user_data: %s&amp;quot;, me)
            return {
                &amp;#x27;username&amp;#x27; : me[&amp;#x27;preferred_username&amp;#x27;],
                &amp;#x27;name&amp;#x27; : me[&amp;#x27;name&amp;#x27;],
                &amp;#x27;email&amp;#x27; : me[&amp;#x27;email&amp;#x27;],
                &amp;#x27;first_name&amp;#x27;: me[&amp;#x27;given_name&amp;#x27;],
                &amp;#x27;last_name&amp;#x27;: me[&amp;#x27;family_name&amp;#x27;],
                &amp;#x27;roles&amp;#x27;: me[&amp;#x27;roles&amp;#x27;],
                &amp;#x27;is_active&amp;#x27;: True,
            }

    def auth_user_oauth(self, userinfo):
        user = super(CustomSsoSecurityManager, self).auth_user_oauth(userinfo)
        roles = [self.find_role(x) for x in userinfo[&amp;#x27;roles&amp;#x27;]]
        roles = [x for x in roles if x is not None]
        user.roles = roles
        logger.debug(&amp;#x27; Update &amp;lt;User: %s&amp;gt; role to %s&amp;#x27;, user.username, roles)
        self.update_user(user)  # update user roles
        return user
&lt;/pre&gt;
  &lt;p id=&quot;Zifb&quot;&gt;and in anycodings_python  /app/pythonpath/superset_config.py I anycodings_python  added some configs -&lt;/p&gt;
  &lt;pre id=&quot;3Byv&quot;&gt;
from flask_appbuilder.security.manager import AUTH_OAUTH, AUTH_REMOTE_USER

from custom_sso_security_manager import CustomSsoSecurityManager
CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager

oauthSecretPair = env(&amp;#x27;OAUTH_CLIENT_ID&amp;#x27;) + &amp;#x27;:&amp;#x27; + env(&amp;#x27;OAUTH_CLIENT_SECRET&amp;#x27;)

AUTH_TYPE = AUTH_OAUTH

OAUTH_PROVIDERS = [
    {   &amp;#x27;name&amp;#x27;:&amp;#x27;keycloak&amp;#x27;,
        &amp;#x27;token_key&amp;#x27;:&amp;#x27;access_token&amp;#x27;, # Name of the token in the response of access_token_url
        &amp;#x27;icon&amp;#x27;:&amp;#x27;fa-address-card&amp;#x27;,   # Icon for the provider
        &amp;#x27;remote_app&amp;#x27;: {
            &amp;#x27;api_base_url&amp;#x27;: env(&amp;#x27;KEYCLOAK_BASE_URL&amp;#x27;, &amp;#x27;http://CHANGEME&amp;#x27;),
            &amp;#x27;client_id&amp;#x27;:env(&amp;#x27;OAUTH_CLIENT_ID&amp;#x27;),  # Client Id (Identify Superset application)
            &amp;#x27;client_secret&amp;#x27;:env(&amp;#x27;OAUTH_CLIENT_SECRET&amp;#x27;), # Secret for this Client Id (Identify Superset application)
            &amp;#x27;client_kwargs&amp;#x27;:{
                &amp;#x27;scope&amp;#x27;: &amp;#x27;profile&amp;#x27;               # Scope for the Authorization
            },
            &amp;#x27;request_token_url&amp;#x27;:None,
            &amp;#x27;access_token_url&amp;#x27;: env(&amp;#x27;KEYCLOAK_BASE_URL&amp;#x27;, &amp;#x27;http://CHANGEME&amp;#x27;) + &amp;#x27;/token&amp;#x27;,
            &amp;#x27;authorize_url&amp;#x27;: env(&amp;#x27;KEYCLOAK_BASE_URL&amp;#x27;, &amp;#x27;http://CHANGEME&amp;#x27;) + &amp;#x27;/auth&amp;#x27;,
        }
    }
]

# Will allow user self registration, allowing to create Flask users from Authorized User
AUTH_USER_REGISTRATION = True

# The default user self registration role
AUTH_USER_REGISTRATION_ROLE = &amp;quot;Gamma&amp;quot;

# This will make sure the redirect_uri is properly computed, even with SSL offloading
ENABLE_PROXY_FIX = True
&lt;/pre&gt;
  &lt;p id=&quot;VBrO&quot;&gt;There are a few env parameters that anycodings_python  these configs expect -&lt;/p&gt;
  &lt;pre id=&quot;K9bT&quot;&gt;KEYCLOAK_BASE_URL
OAUTH_CLIENT_ID
OAUTH_CLIENT_SECRET
&lt;/pre&gt;
  &lt;p id=&quot;7Zal&quot;&gt;0&lt;/p&gt;
  &lt;h2 id=&quot;zi4C&quot;&gt;&lt;strong&gt;Answers 3 :&lt;/strong&gt; of Using OpenIDKeycloak with Superset&lt;/h2&gt;
  &lt;p id=&quot;JKOj&quot;&gt;I tried to follow the tips based on the anycodings_python  comments in this post, but even so, anycodings_python  there were still other doubts along the anycodings_python  process, and I managed to solve the anycodings_python  problem and it works perfectly, I would anycodings_python  like to share the code to solve the anycodings_python  problem superset-keycloak. This aprouch anycodings_python  use docker to deploy the superset anycodings_python  application.&lt;/p&gt;

</content></entry></feed>