mirror of
https://github.com/opentofu/opentofu.org.git
synced 2026-01-11 19:56:26 +00:00
Ephemeral blog post (#384)
Signed-off-by: Christian Mesh <christianmesh1@gmail.com> Signed-off-by: James Humphries <james@james-humphries.co.uk> Co-authored-by: James Humphries <James@james-humphries.co.uk> Co-authored-by: Ilia Gogotchuri <ilia.gogotchuri0@gmail.com>
This commit is contained in:
parent
3f3db1835a
commit
c74c653a5f
8 changed files with 101 additions and 88 deletions
|
|
@ -19,6 +19,7 @@ module.exports = {
|
|||
"react/no-unescaped-entities": ["error", { forbid: [">", "}"] }],
|
||||
"jsx-a11y/click-events-have-key-events": "off",
|
||||
"jsx-a11y/no-static-element-interactions": "off",
|
||||
"max-len": ["error", { code: 200 }],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
|
|
|
|||
49
blog/2025-09-11-ephemeral-ready-for-testing.md
Normal file
49
blog/2025-09-11-ephemeral-ready-for-testing.md
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
title: Ephemeral Support in OpenTofu
|
||||
slug: ephemeral-ready-for-testing
|
||||
---
|
||||
|
||||
We are excited to announce the availability of Ephemeral and Write-Only features in the latest nightly builds of OpenTofu!
|
||||
|
||||
This is a [highly requested feature](https://github.com/opentofu/opentofu/issues/1996) that we have been hard at work on for a while now. All the necessary components have now been merged and are available in the nightly builds of OpenTofu and will be available in the upcoming 1.11 release.
|
||||
|
||||
:::warning
|
||||
|
||||
Do not test this release on a production project! It is not a stable release!
|
||||
|
||||
:::
|
||||
|
||||
## Downloading the nightly builds
|
||||
|
||||
The nightly builds are available exclusively from the [OpenTofu Nightly Repository](https://nightlies.opentofu.org/nightlies/). Please choose the select the appropriate file for your platform.
|
||||
|
||||
## Ephemeral Overview
|
||||
|
||||
A long-standing issue with OpenTofu and its predecessor has been the storage of sensitive data within the state. Prior to Ephemeral, this data contained everything that OpenTofu knows about the resources it manages. This includes sensitive values, keys, and other secrets that could lead to security incidents if leaked. The introduction of Ephemeral and Write-Only allows for careful configuration to prevent storing this secret data, ensuring that these values only exist within the duration of a single execution of the `tofu` binary. It also allows for transient resources, such as network tunnels, to be made available during specific portions of the OpenTofu Plan/Apply flow.
|
||||
|
||||
### Prior Solutions
|
||||
|
||||
As many seasoned OpenTofu and Terraform authors know, values and attributes can be marked as [Sensitive](/docs/language/functions/sensitive/) to prevent them from being displayed in the CLI. This helps prevent accidental exposure of secrets through CI/CD logs and other mechanisms. It still however stores the plain text data in the state.
|
||||
|
||||
To remedy this, OpenTofu introduced [State and Plan Encryption](/docs/language/state/encryption/). This feature allows you to carefully protect your plan and state data, as well as ensuring that they have not been tampered with in transport. Although the values are still stored within the state and plan, this adds an additional level of security to make it much more difficult for attackers to gain access. It protects the entire state and plan, regardless of how individual resources are configured or marked. Therefore it is still recommended to use state and plan encryption, even after adopting Ephemeral concepts into your workflow.
|
||||
|
||||
### Ephemeral Resources
|
||||
|
||||
[Ephemeral Resources](/docs/main/language/ephemerality/ephemeral-resources/) are entities that only exist during the execution of a single command. They are opened at the beginning of an OpenTofu operation to get their ephemeral value and closed at the end of the operation. These resources can represent anything from keys in a Key Management System to a SSH proxy that is established when the resource is opened.
|
||||
|
||||
The attributes of Ephemeral Resources are marked as `ephemeral` and as such can only be used in [very specific contexts](/docs/main/language/ephemerality/ephemeral-resources/).
|
||||
|
||||
### Write-Only Attributes
|
||||
|
||||
[Write-Only](/docs/main/language/ephemerality/write-only-attributes/) attributes are a special case that has been added to Managed Resources to allow passing ephemeral data into non-ephemeral resources. These attributes can be set in configuration, but their values will never be stored in state or even available as an attribute to be accessed in other portions of the configuration.
|
||||
|
||||
This is geared toward sending ephemeral data, such as passwords and keys, into resources which use and/or manage this data outside of OpenTofu.
|
||||
|
||||
|
||||
### Further Reading
|
||||
|
||||
This blog post barely scratches the surface of what is now possible with Ephemeral and Write-Only. Peruse our latest docs for a more [complete overview and in-depth examples](/docs/main/language/ephemerality/)!
|
||||
|
||||
## Providing feedback
|
||||
|
||||
Thank you for taking the time to test this preview release. If you have any feedback, please use [a GitHub issue](https://github.com/opentofu/opentofu/issues/new/choose) or chat with us on the [OpenTofu Slack](https://opentofu.org/slack/).
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 23d2eafe670bb8c4f57e0749e74be134c9003b0d
|
||||
Subproject commit 79e5070b47805816e7387b925bcb1a174f58d0b0
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
import React from "react";
|
||||
import PatternBg from "@site/src/components/PatternBg";
|
||||
import Button from "@site/src/components/Button";
|
||||
import Link from "@docusaurus/Link";
|
||||
import { PropBlogPostContent } from "@docusaurus/plugin-content-blog";
|
||||
|
||||
type BlogLastPostProps = {
|
||||
item: {
|
||||
content: PropBlogPostContent;
|
||||
};
|
||||
};
|
||||
|
||||
export default function BlogLastPost({ item }: BlogLastPostProps) {
|
||||
const { permalink, title, date, formattedDate, description } =
|
||||
item.content.metadata;
|
||||
|
||||
return (
|
||||
<div className="pt-8 pb-12 md:pt-12 md:pb-20 flex items-center justify-center">
|
||||
<PatternBg />
|
||||
<div className="max-w-7xl mx-auto px-4">
|
||||
<article>
|
||||
<div className="flex flex-col md:flex-row gap-6">
|
||||
<div className="flex-1">
|
||||
<Link to={permalink}>
|
||||
<img src={item.content.frontMatter.image} alt={title} />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex-1 flex flex-col justify-center items-start">
|
||||
<time
|
||||
dateTime={date}
|
||||
itemProp="datePublished"
|
||||
className="text-brand-650 dark:text-brand-500 uppercase font-bold"
|
||||
>
|
||||
{formattedDate}
|
||||
</time>
|
||||
|
||||
<h3 className="leading-snug text-3xl font-bold my-2 line-clamp-5">
|
||||
<Link
|
||||
to={permalink}
|
||||
className="text-gray-900 dark:text-gray-50 hover:text-brand-650 dark:hover:text-brand-500"
|
||||
>
|
||||
{title}
|
||||
</Link>
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-500 mb-4 line-clamp-3">
|
||||
{description}
|
||||
</p>
|
||||
<Button variant="secondary" href={permalink}>
|
||||
<span aria-hidden>Read More</span>
|
||||
<span className="sr-only">Read more about: ${title}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
import Link from "@docusaurus/Link";
|
||||
import Button from "@site/src/components/Button";
|
||||
import React from "react";
|
||||
import { PropBlogPostContent } from "@docusaurus/plugin-content-blog";
|
||||
|
||||
|
|
@ -7,29 +6,35 @@ type BlogListItemProps = {
|
|||
item: {
|
||||
content: PropBlogPostContent;
|
||||
};
|
||||
isLatestPost?: boolean;
|
||||
};
|
||||
|
||||
export default function BlogListItem({ item }: BlogListItemProps) {
|
||||
export default function BlogListItem({
|
||||
item,
|
||||
isLatestPost: isLatest = false,
|
||||
}: BlogListItemProps) {
|
||||
const { permalink, title, date, formattedDate, description } =
|
||||
item.content.metadata;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex gap-6">
|
||||
<div className="flex-1">
|
||||
<Link to={permalink}>
|
||||
<img src={item.content.frontMatter.image} alt={title} />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex-1 flex flex-col justify-center items-start">
|
||||
<time
|
||||
dateTime={date}
|
||||
itemProp="datePublished"
|
||||
className="text-brand-650 dark:text-brand-500 uppercase font-bold"
|
||||
>
|
||||
{formattedDate}
|
||||
</time>
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<time
|
||||
dateTime={date}
|
||||
itemProp="datePublished"
|
||||
className="text-brand-650 dark:text-brand-500 uppercase font-bold"
|
||||
>
|
||||
{formattedDate}
|
||||
</time>
|
||||
{isLatest && (
|
||||
<span className="inline-flex px-3 py-1 text-sm font-medium rounded-full bg-blue-600/90 text-white dark:bg-blue-500/90">
|
||||
Latest
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<h3 className="leading-snug text-xl font-bold my-2 line-clamp-3">
|
||||
<h3 className="leading-snug text-xl font-bold mt-2 mb-2 line-clamp-3">
|
||||
<Link
|
||||
to={permalink}
|
||||
className="text-gray-900 dark:text-gray-50 hover:text-brand-650 dark:hover:text-brand-500"
|
||||
|
|
@ -40,11 +45,24 @@ export default function BlogListItem({ item }: BlogListItemProps) {
|
|||
<p className="text-gray-600 dark:text-gray-500 mb-4 line-clamp-3">
|
||||
{description}
|
||||
</p>
|
||||
<Button variant="secondary" href={permalink}>
|
||||
<span aria-hidden>Read More</span>
|
||||
<span className="sr-only">Read more about: ${title}</span>
|
||||
</Button>
|
||||
<Link
|
||||
to={permalink}
|
||||
className="text-brand-650 dark:text-brand-500 hover:text-brand-700 dark:hover:text-brand-400 text-sm font-medium"
|
||||
>
|
||||
Read More →
|
||||
</Link>
|
||||
</div>
|
||||
{item.content.frontMatter.image && (
|
||||
<div className="w-32 flex items-center">
|
||||
<Link to={permalink} className="block w-full">
|
||||
<img
|
||||
src={item.content.frontMatter.image}
|
||||
alt={title}
|
||||
className="w-full h-auto object-cover rounded"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,13 @@ type BlogListItemsProps = {
|
|||
|
||||
export default function BlogListItems({ items }: BlogListItemsProps) {
|
||||
return (
|
||||
<div className="max-w-7xl mx-auto grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-x-6 gap-y-12 py-4 md:py-10 px-4">
|
||||
{items.map((item) => (
|
||||
<BlogListItem item={item} key={item.content.metadata.permalink} />
|
||||
<div className="max-w-7xl mx-auto space-y-8 px-4">
|
||||
{items.map((item, index) => (
|
||||
<BlogListItem
|
||||
item={item}
|
||||
key={item.content.metadata.permalink}
|
||||
isLatestPost={index === 0}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,23 +5,20 @@ import BlogLayout from "@theme/BlogLayout";
|
|||
import BlogListPaginator from "@theme/BlogListPaginator";
|
||||
import SearchMetadata from "@theme/SearchMetadata";
|
||||
import BlogListItems from "@theme/BlogListItems";
|
||||
import BlogLastPost from "@theme/BlogLastPost";
|
||||
import { Props } from "@theme/BlogListPage";
|
||||
import PatternBg from "@site/src/components/PatternBg";
|
||||
|
||||
export default function BlogListPage(props: Props) {
|
||||
const { metadata, items } = props;
|
||||
const { blogDescription, blogTitle } = metadata;
|
||||
|
||||
const lastPost = items[0];
|
||||
const otherPosts = items.slice(1);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageMetadata title={blogTitle} description={blogDescription} />
|
||||
<SearchMetadata tag="blog_posts_list" />
|
||||
<PatternBg />
|
||||
<BlogLayout>
|
||||
<BlogLastPost item={lastPost} />
|
||||
<BlogListItems items={otherPosts} />
|
||||
<BlogListItems items={items} />
|
||||
<BlogListPaginator metadata={metadata} />
|
||||
</BlogLayout>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -74,9 +74,11 @@ export default function BlogPostItem({ children }: Props) {
|
|||
<BlogPostItemContainer>
|
||||
<BlogPostItemHeader />
|
||||
|
||||
{ frontMatter.image &&
|
||||
<div className="max-w-5xl mx-auto flex justify-center">
|
||||
<img src={frontMatter.image} alt={title} />
|
||||
</div>
|
||||
}
|
||||
<div className="max-w-5xl mx-auto flex flex-col justify-center relative">
|
||||
<div className="lg:sticky top-0">
|
||||
<div className="flex justify-center mb-4 md:mb-10 lg:flex-col relative lg:absolute right-0 top-4 md:top-10 gap-4">
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue